Docker容器间Java Spring Boot应用Rest API通信失败求助
问题描述
本地控制台运行两个Spring Boot应用时正常,Postman调用端点也正常,但Docker化部署后,访问http://localhost:8080/send出现错误:
I/O error on POST request for "http://localhost:8081/processString": Connection refused.
代码与配置信息
LogonPageApplication(端口8080)
@SpringBootApplication @RestController public class LogonPageApplication { private static final String PROCESS_STRING_URL = "http://localhost:8081/processString"; public static void main(String[] args) { SpringApplication.run(LogonPageApplication.class, args); } @GetMapping("/send") public String test() { String responseBody = ""; try { RestTemplate restTemplate = new RestTemplate(); HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); String requestBody = "{testttgfvrdf}"; HttpEntity<String> httpEntity = new HttpEntity<>(requestBody, headers); ResponseEntity<String> response = restTemplate.exchange(PROCESS_STRING_URL, HttpMethod.POST, httpEntity, String.class); responseBody = response.getBody(); } catch (Exception e) { return e.getMessage(); } return "Main Page\n" + "Response from /processString: " + responseBody; } }
AcceptMessageApplication(端口8081)
@SpringBootApplication @RestController public class AcceptMessageApplication { public static void main(String[] args) { SpringApplication.run(AcceptMessageApplication.class, args); } @PostMapping("/processString") public String processString(@RequestBody String inputString) { return "Processed string: " + inputString; } }
Dockerfile示例(两个应用的Dockerfile需对应自身jar包)
FROM openjdk:17-jdk-slim WORKDIR /app COPY target/AcceptMessage-0.0.1-SNAPSHOT.jar /app/AcceptMessage-0.0.1-SNAPSHOT.jar EXPOSE 8080 CMD ["java", "-jar", "AcceptMessage-0.0.1-SNAPSHOT.jar"]
注:LogonPage的Dockerfile需将COPY和CMD中的jar包名称替换为自身项目的jar,比如LogonPage-0.0.1-SNAPSHOT.jar
docker-compose.yml
version: '3' services: appacc: build: context: AcceptMessage dockerfile: Dockerfile ports: - "8081:8080" networks: - my-network applog: build: context: LogonPage dockerfile: Dockerfile ports: - "8080:8080" networks: - my-network networks: my-network: # docker-compose build # docker-compose up
问题原因
容器内的localhost指向容器自身,而非宿主机。当applog容器尝试访问http://localhost:8081时,实际是在访问自己容器的8081端口,而该端口并未对外开放,因此出现连接拒绝错误。
Docker Compose创建的自定义网络中,容器之间可以通过服务名称直接通信,无需使用宿主机的端口映射。appacc服务的内部端口是8080(容器自身运行的端口),宿主机的8081端口只是对外映射的端口,容器间通信不需要走这个映射端口。
解决方案
修改LogonPageApplication中的请求地址
将PROCESS_STRING_URL的值改为http://appacc:8080/processString,其中appacc是docker-compose.yml中定义的服务名称,容器会自动解析该名称到对应的容器IP地址:private static final String PROCESS_STRING_URL = "http://appacc:8080/processString";修正LogonPage的Dockerfile
确保LogonPage的Dockerfile中COPY和CMD指向的是自身项目的jar包,避免因jar包名称错误导致容器无法启动:FROM openjdk:17-jdk-slim WORKDIR /app COPY target/LogonPage-0.0.1-SNAPSHOT.jar /app/LogonPage-0.0.1-SNAPSHOT.jar EXPOSE 8080 CMD ["java", "-jar", "LogonPage-0.0.1-SNAPSHOT.jar"]重新构建并启动服务
执行以下命令重新构建镜像并启动容器:docker-compose build docker-compose up
完成以上步骤后,访问http://localhost:8080/send即可正常获取appacc服务的响应。
内容的提问来源于stack exchange,提问作者Kefest1

