解决Docker Compose中Next.js、Payload CMS与MongoDB的ECONNREFUSED错误
多容器Docker Compose环境通信问题排查与解决
问题背景
使用Docker Compose搭建Next.js(blueastowel)、Payload CMS(payload)、MongoDB(mongo)多容器环境时,遇到两个核心问题:
- 初始配置下,blueastowel连接payload时出现
ECONNREFUSED ::1:3001错误 - 修改环境变量后文本可加载,但前端无法获取媒体资源,提示
ERR_NAME_NOT_RESOLVED(无法解析payload:3000地址)
初始错误日志
blueastowel-1 | TypeError: fetch failed blueastowel-1 | at node:internal/deps/undici/undici:12618:11 blueastowel-1 | at process.processTicksAndRejections (node:internal/process/task_queues:95:5) blueastowel-1 | at async u (/app/.next/server/pages/api/about-us.js:1:605) { blueastowel-1 | cause: Error: connect ECONNREFUSED ::1:3001 blueastowel-1 | at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1555:16) blueastowel-1 | at TCPConnectWrap.callbackTrampoline (node:internal/async_hooks:128:17) { blueastowel-1 | errno: -111, blueastowel-1 | code: 'ECONNREFUSED', blueastowel-1 | syscall: 'connect', blueastowel-1 | address: '::1', blueastowel-1 | port: 3001 blueastowel-1 | } blueastowel-1 | }
修改后媒体资源错误日志
payload:3000/media/W…at%2016.20.20.jpg:1 GET http://payload:3000/media/WhatsApp%20Image%202024-04-24%20at%2016.20.20.jpg net::ERR_NAME_NOT_RESOLVED
问题分析与解决方案
1. 容器端口映射混淆问题
payload容器的端口配置为3001:3000,其中:
3000是容器内部服务监听的端口3001是宿主机映射的外部端口
容器间通信必须使用容器内部端口,初始配置中NEXT_PUBLIC_PAYLOAD_APP_URL=http://payload:3001错误使用了外部映射端口,导致连接失败。
2. 区分服务端与客户端环境变量
Next.js中,带NEXT_PUBLIC_前缀的环境变量会被暴露给浏览器,而浏览器无法解析Docker内部的服务名(如payload),这是媒体资源加载失败的核心原因。
修改blueastowel的环境变量,分离服务端内部通信与客户端外部访问地址:
blueastowel: # ...其他配置 environment: - PAYLOAD_APP_URL=http://payload:3000 # 服务端内部调用Payload API用 - NEXT_PUBLIC_PAYLOAD_PUBLIC_URL=http://localhost:3001 # 客户端浏览器访问媒体资源用 - PAYLOAD_API_KEY=50ab8231-770c-4fb9-9ec5-e1ce67650270 - PAYLOAD_API_SLUG=users - URL=http://localhost:3000 - NODE_ENV=production
3. 确保Payload服务就绪后启动Next.js
depends_on仅保证容器启动顺序,不确保服务已就绪。添加健康检查,让blueastowel在Payload完全启动后再启动:
给payload服务添加健康检查:
payload: # ...其他配置 healthcheck: test: ["CMD", "curl", "-f", "http://localhost:3000/health"] interval: 10s timeout: 5s retries: 5
修改blueastowel的depends_on配置:
blueastowel: # ...其他配置 depends_on: payload: condition: service_healthy
4. 配置Payload的外部访问地址
确保Payload返回的媒体资源URL是浏览器可访问的外部地址,在Payload的payload.config.ts中配置serverURL:
export default buildConfig({ serverURL: process.env.PAYLOAD_PUBLIC_SERVER_URL || 'http://localhost:3001', // ...其他配置项 });
同时给payload容器添加对应环境变量:
payload: # ...其他配置 environment: # ...已有变量 - PAYLOAD_PUBLIC_SERVER_URL=http://localhost:3001
内容的提问来源于stack exchange,提问作者sayinmehmet47
相关产品推荐
相关产品推荐

