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

Java启动Docker镜像HTTP访问异常问题求助

Java应用调用Docker Socket创建容器后HTTP访问失败(终端执行正常)

我正在开发一款Heroku替代方案,遇到以下问题:

  • 在终端直接执行curl命令调用Docker Socket创建Nginx容器,能正常获取容器ID并成功运行
  • 通过Spring Boot应用的HTTP接口触发相同的容器创建逻辑后,访问对应端口显示错误页面

相关截图

  • 终端正常运行截图:终端正常运行截图
  • 错误页面截图:错误页面截图

核心代码片段

创建容器的curl命令:

String command = "curl --silent -XPOST --unix-socket /run/docker.sock -d '{\"Image\":\"nginx:latest\"}' -H 'Content-Type: application/json' http://localhost/containers/create?name=nginx";

完整Controller代码

package com.handson.chatbot.controller;

import com.handson.chatbot.model.StudentApplication;
import com.handson.chatbot.repo.StudentApplicationsService;
import kotlin.Pair;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.PathMatcher;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.servlet.HandlerMapping;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import java.io.*;
import java.sql.Timestamp;
import java.util.*;
import java.util.concurrent.TimeUnit;


@RestController
@RequestMapping("/app")
public class AppController {

    Map<String, Long> aliasToLastCalledTime = new HashMap<>();
    @Autowired
    StudentApplicationsService studentService;

    @Autowired
    private PathMatcher pathMatcher;

    @Autowired
    private RestTemplate restTemplate;
    OkHttpClient client = new OkHttpClient().newBuilder()
            .build();

    private String getWildcardParam(HttpServletRequest request) {
        String patternAttribute = (String) request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE);
        String mappingAttribute = (String) request.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE);
        return this.pathMatcher.extractPathWithinPattern(patternAttribute, mappingAttribute);
    }

    // create api to register applications (student-docker, appid, = store in database with port
    // apps (docker_image, appid, port)

    @RequestMapping(method = RequestMethod.GET, value = "/{alias}/**")
    public void getItem(HttpServletRequest request, @PathVariable String alias, HttpServletResponse response) throws IOException, InterruptedException {
        String wantedApp = alias;
        System.out.println("request for app:" + wantedApp);
        // check on database for the student of app
        // random student between 9000 - 20000
        // String student = "9001"; // get this from database according to appid
        StudentApplication studentApplication = studentService.getStudentApplicationByAlias(wantedApp);
        System.out.println(studentApplication);

        ////////

        String dockerImage = studentApplication.getDocker_image();
        try {
            forwardGetRequestToApp(request, response, studentApplication.getPort());
        } catch (Exception e) {
            // start docker image
//            String command1 = "sudo service docker start";
//            Process p1 = Runtime.getRuntime().exec(new String[]{"bash", "-c", command1});
//            String command = "curl --unix-socket /var/run/docker.sock -H \"Content-Type: application/json\"  -d '{\"Image\": \"redis\"}' " +
//                    "  -X POST http://localhost/v1.41/containers/create";
            String command = "curl --silent -XPOST --unix-socket /run/docker.sock -d '{\"Image\":\"nginx:latest\"}' -H 'Content-Type: application/json' http://localhost/containers/create?name=nginx";


            String p = executeShell(command);
            System.out.println(p);
//            java.util.Scanner s = new java.util.Scanner(p.getInputStream());
//            System.out.println(s.nextLine());
            // wait for 30 seconds
            TimeUnit.SECONDS.sleep(30);
            forwardGetRequestToApp(request, response, studentApplication.getPort());
        }

        // save the last timestamp for each application
        Timestamp timestamp = new Timestamp(System.currentTimeMillis());
        long timestampToMinutes = TimeUnit.MILLISECONDS.toMinutes(timestamp.getTime());
        aliasToLastCalledTime.put(wantedApp, timestampToMinutes);


        Timer timer = new Timer();

        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                Timestamp currentTime = new Timestamp(System.currentTimeMillis());

                for (Map.Entry<String, Long> ts : aliasToLastCalledTime.entrySet()) {
                    if ((TimeUnit.MILLISECONDS.toMinutes(currentTime.getTime()) - ts.getValue()) >= 30) {
                        // kill docker that was not used for 30 minutes

                    }
                }

            }
        }, 0, 60 * 1000);

    }

    private void forwardGetRequestToApp(HttpServletRequest request, HttpServletResponse response, Integer port) throws IOException {
        String url = "http://localhost:" + port + "/" + this.getWildcardParam(request);
        //ResponseEntity res = this.restTemplate.getForEntity(url, String.class);
        Request.Builder builder = new Request.Builder()
                .url(url)
                .get();
        String h = null;
        Enumeration<String> headerNames = request.getHeaderNames();
        while (headerNames.hasMoreElements()) {
            h = headerNames.nextElement();
            builder.addHeader(h, request.getHeader(h));
        }
        Response response1 = client.newCall(builder.build()).execute();

        response.setContentLength((int) response1.body().contentLength());
        byte[] buffer = new byte[10240];

        try (
                OutputStream output = response.getOutputStream();
        ) {
            for (int length = 0; (length = response1.body().byteStream().read(buffer)) > 0; ) {
                output.write(buffer, 0, length);
            }
        }
        Iterator<Pair<String, String>> h2 = response1.headers().iterator();
        while (h2.hasNext()) {
            Pair<String, String> h3 = h2.next();
            response.addHeader(h3.component1(), h3.component2());
        }
    }

    private String executeShell(String cmd) throws InterruptedException, IOException {
        String res = "";
        String line;
        OutputStream stdin;
        InputStream stderr;
        InputStream stdout;

        System.out.println("executing:\n" + cmd);
        Process process = Runtime.getRuntime().exec(cmd);

        stdin = process.getOutputStream();
        stderr = process.getErrorStream();
        stdout = process.getInputStream();

        line = "\n";
        stdin.write(line.getBytes());
        stdin.flush();

        stdin.write(line.getBytes());
        stdin.flush();

        stdin.close();

        BufferedReader brCleanUp = new BufferedReader(new InputStreamReader(stdout));
        while ((line = brCleanUp.readLine()) != null) {
            res += line + "\n";
            System.out.println(line);
        }
        brCleanUp.close();

        brCleanUp = new BufferedReader(new InputStreamReader(stderr));
        while ((line = brCleanUp.readLine()) != null) {
            System.out.println("Abnormal process termination" + line);
            throw new RuntimeException("process failed and: " + line);
        }
        brCleanUp.close();

        int exitValue = process.exitValue();
        if (exitValue > 0) {

            throw new RuntimeException("exit value: " + String.valueOf(exitValue));


        }
        return res;
    }


}

预期与实际结果

  • 预期:通过HTTP端口访问到Docker容器运行的Nginx服务
  • 实际:访问后显示错误页面

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 01:10:27