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

如何在Docker容器内的PHP Laravel中调用宿主机Docker创建容器

问题场景

我们用Docker运行PHP Laravel作为API服务器,需要从容器内调用宿主机的Docker创建并运行新容器(非Docker-in-Docker场景)。尝试了两种基于Docker API的curl方法均失败:

方法1:PHP curl扩展调用

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "http://localhost/containers/create");
curl_setopt($ch, CURLOPT_UNIX_SOCKET_PATH, "/var/run/docker.sock");
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Content-Type: application/json',
]);

$response = curl_exec($ch);
$error = curl_error($ch);
curl_close($ch);

执行结果:

{
    "error": "Couldn't connect to server"
}

方法2:shell_exec执行curl命令

$createCommand = sprintf(
"curl --unix-socket /var/run/docker.sock -H 'Content-Type: application/json' -d '%s' -X POST http://localhost/v1.47/containers/create 2>&1",
json_encode([
    'Image' => 'test-image',
    'Cmd' => ['python3', 'main.py', $args1, $args2],
])
);

$createOutput = shell_exec($createCommand);

执行结果:

curl (7) failed to connect

解决方案

核心问题是容器内无法访问宿主机的/var/run/docker.sock,需先完成挂载权限配置,再修正调用逻辑:

1. 挂载宿主机Docker套接字到Laravel容器

启动Laravel容器时,通过-v参数将宿主机的Docker套接字映射到容器内,同时确保容器内用户有读写权限:

docker run -d \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -v /usr/bin/docker:/usr/bin/docker \
  --user root \
  your-laravel-image:tag
  • -v /var/run/docker.sock:/var/run/docker.sock:将宿主机的Docker套接字映射到容器内,让容器能通过套接字调用宿主机Docker API
  • -v /usr/bin/docker:/usr/bin/docker:可选,若需直接在容器内执行docker命令,挂载宿主机的docker二进制文件
  • --user root:确保容器内用户对套接字有读写权限(生产环境可精细化配置,比如将容器用户加入宿主机docker用户组)

2. 修正PHP curl调用逻辑

需指定Docker API版本(如v1.47),同时补充容器启动逻辑:

$payload = json_encode([
    'Image' => 'test-image',
    'Cmd' => ['python3', 'main.py', $args1, $args2],
    // 可添加端口映射、卷挂载等其他容器配置
]);

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "http://localhost/v1.47/containers/create");
curl_setopt($ch, CURLOPT_UNIX_SOCKET_PATH, "/var/run/docker.sock");
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Content-Type: application/json',
]);

$response = curl_exec($ch);
if ($response === false) {
    $error = curl_error($ch);
    // 处理错误逻辑
} else {
    $containerInfo = json_decode($response, true);
    // 创建成功后启动容器
    $startCh = curl_init();
    curl_setopt($startCh, CURLOPT_URL, "http://localhost/v1.47/containers/{$containerInfo['Id']}/start");
    curl_setopt($startCh, CURLOPT_UNIX_SOCKET_PATH, "/var/run/docker.sock");
    curl_setopt($startCh, CURLOPT_POST, true);
    curl_setopt($startCh, CURLOPT_RETURNTRANSFER, true);
    $startResponse = curl_exec($startCh);
    curl_close($startCh);
}
curl_close($ch);

3. 修正shell_exec调用的转义问题

方法2中json_encode后的字符串含引号,直接拼接会导致shell语法错误,需转义特殊字符:

$containerConfig = json_encode([
    'Image' => 'test-image',
    'Cmd' => ['python3', 'main.py', $args1, $args2],
]);
// 转义shell特殊字符避免语法错误
$escapedConfig = escapeshellarg($containerConfig);

$createCommand = sprintf(
"curl --unix-socket /var/run/docker.sock -H 'Content-Type: application/json' -d %s -X POST http://localhost/v1.47/containers/create 2>&1",
$escapedConfig
);

$createOutput = shell_exec($createCommand);

4. 权限排查(关键)

若挂载后仍无法连接,检查以下内容:

  • 宿主机/var/run/docker.sock的权限:执行ls -l /var/run/docker.sock,确保所属组为docker,权限为rw-rw----
  • 容器内用户组配置:若未用root用户,可在Dockerfile中添加RUN usermod -aG docker www-data(假设Laravel运行用户为www-data),同时确保宿主机docker组GID与容器内一致

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 07:27:35