容器内通过Docker Socket执行PHP Curl请求失败求助
PHP通过Unix Socket调用Docker API失败排查
问题描述
我在Docker容器中运行PHP代码,想要执行等效于curl --unix-socket /var/run/docker.sock http://localhost/v1.40/containers/json的操作,获取宿主机上的容器列表。尝试了相关帖子中的两种方法,但既没有响应,STDERR也无输出,常遇到“Connection Failure”错误,curl_getinfo()返回的信息中http_code为0,各项传输相关数值均为0。
我的代码
<?php function callAPI($method, $url, $data){ $curl = curl_init(); curl_setopt($curl, CURLOPT_UNIX_SOCKET_PATH, "/var/run/docker.sock"); curl_setopt($curl, CURLOPT_VERBOSE, true); switch ($method){ case "POST": curl_setopt($curl, CURLOPT_POST, 1); if ($data) curl_setopt($curl, CURLOPT_POSTFIELDS, $data); break; case "PUT": curl_setopt($curl, CURLOPT_CUSTOMREQUEST, "PUT"); if ($data) curl_setopt($curl, CURLOPT_POSTFIELDS, $data); break; default: if ($data) $url = sprintf("%s?%s", $url, http_build_query($data)); } // OPTIONS: curl_setopt($curl, CURLOPT_URL, $url); curl_setopt($curl, CURLOPT_HTTPHEADER, array( 'Content-Type: application/json' )); curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); // EXECUTE: $result = curl_exec($curl); // echo $result; print_r($result); if(!$result){die("Connection Failure");} $info = curl_getinfo($curl); print_r($info); curl_close($curl); return $result; } $get_data = callAPI("GET","http://localhost/v1.40/containers/json", false); print_r($get_data); $response = json_decode($get_data, true); $errors = $response['response']['errors']; print_r($response); echo $data; echo $errors; ?>
错误输出
Array ( [url] => http://localhost/v1.40/containers/json [content_type] => [http_code] => 0 [header_size] => 0 [request_size] => 0 [filetime] => -1 [ssl_verify_result] => 0 [redirect_count] => 0 [total_time] => 0 [namelookup_time] => 2.1E-5 [connect_time] => 0 [pretransfer_time] => 0 [size_upload] => 0 [size_download] => 0 [speed_download] => 0 [speed_upload] => 0 [download_content_length] => -1 [upload_content_length] => -1 [starttransfer_time] => 0 [redirect_time] => 0 [redirect_url] => [primary_ip] => [certinfo] => Array ( ) [primary_port] => 0 [local_ip] => [local_port] => 0 [http_version] => 0 [protocol] => 0 [ssl_verifyresult] => 0 [scheme] => )
问题排查与解决方法
1. 容器挂载与权限验证
首先确认容器是否正确挂载宿主机的/var/run/docker.sock,且PHP进程有读写权限:
- 启动容器时必须添加挂载参数:
-v /var/run/docker.sock:/var/run/docker.sock - 检查容器内
/var/run/docker.sock的权限,确保PHP运行用户(通常是www-data)属于docker用户组,可在容器内执行chown root:docker /var/run/docker.sock,或启动容器时指定用户组:--group-add=$(stat -c '%g' /var/run/docker.sock)
2. 调整cURL选项顺序
部分cURL版本中,设置CURLOPT_URL会重置socket相关配置,需先设置URL再指定Unix Socket路径:
// 先设置URL curl_setopt($curl, CURLOPT_URL, $url); // 再设置Unix Socket路径 curl_setopt($curl, CURLOPT_UNIX_SOCKET_PATH, "/var/run/docker.sock");
3. 增强错误排查能力
在curl_exec后添加cURL错误信息输出,替换原die语句:
if(!$result){ echo "cURL Error: " . curl_error($curl); die("Connection Failure"); }
这能直接定位具体错误,比如权限不足、socket文件不存在等。
4. 移除不必要的HTTP头部
Docker API的GET请求不需要Content-Type: application/json头部,可移除避免干扰:
// 仅在POST/PUT请求时添加Content-Type头部 if($method !== "GET"){ curl_setopt($curl, CURLOPT_HTTPHEADER, array( 'Content-Type: application/json' )); }
修改后的示例代码
<?php function callAPI($method, $url, $data){ $curl = curl_init(); // 先设置URL curl_setopt($curl, CURLOPT_URL, $url); // 再设置Unix Socket路径 curl_setopt($curl, CURLOPT_UNIX_SOCKET_PATH, "/var/run/docker.sock"); curl_setopt($curl, CURLOPT_VERBOSE, true); switch ($method){ case "POST": curl_setopt($curl, CURLOPT_POST, 1); if ($data) curl_setopt($curl, CURLOPT_POSTFIELDS, $data); break; case "PUT": curl_setopt($curl, CURLOPT_CUSTOMREQUEST, "PUT"); if ($data) curl_setopt($curl, CURLOPT_POSTFIELDS, $data); break; default: if ($data){ $url = sprintf("%s?%s", $url, http_build_query($data)); // 重新设置带参数的URL curl_setopt($curl, CURLOPT_URL, $url); } } // OPTIONS: // 仅非GET请求添加Content-Type头部 if($method !== "GET"){ curl_setopt($curl, CURLOPT_HTTPHEADER, array( 'Content-Type: application/json' )); } curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); // EXECUTE: $result = curl_exec($curl); // 输出cURL错误信息 if(!$result){ echo "cURL Error: " . curl_error($curl); die("Connection Failure"); } $info = curl_getinfo($curl); print_r($info); curl_close($curl); return $result; } $get_data = callAPI("GET","http://localhost/v1.40/containers/json", false); print_r($get_data); $response = json_decode($get_data, true); print_r($response); ?>
内容的提问来源于stack exchange,提问作者masterlu12
相关产品推荐
相关产品推荐

