Cloud Run部署含Express、Mongoose的Docker容器遇Mongo连接错误
Cloud Run部署Node.js+MongoDB容器无法连接MongoDB的解决方法
问题描述
我尝试在Cloud Run上部署首个容器,使用搭载MongoDB的Node.js服务器。本地通过Docker Compose可正常启动容器,但上传至Cloud Run后,服务器能启动却无法连接MongoDB,控制台报错getaddrinfo ENOTFOUND mongo。相关配置及日志如下:
错误日志
Apr 21 01:12:30 AM MongoServerSelectionError: getaddrinfo ENOTFOUND mongo Apr 21 01:12:30 AM at Timeout._onTimeout (/opt/render/project/src/node_modules/mongodb/lib/sdam/topology.js:277:38) Apr 21 01:12:30 AM at listOnTimeout (internal/timers.js:555:17) Apr 21 01:12:30 AM at processTimers (internal/timers.js:498:7) { Apr 21 01:12:30 AM reason: TopologyDescription { Apr 21 01:12:30 AM type: 'Unknown', Apr 21 01:12:30 AM servers: Map(1) { 'mongo:27017' => [ServerDescription] }, Apr 21 01:12:30 AM stale: false, Apr 21 01:12:30 AM compatible: true, Apr 21 01:12:30 AM heartbeatFrequencyMS: 10000, Apr 21 01:12:30 AM localThresholdMS: 15, Apr 21 01:12:30 AM setName: null, Apr 21 01:12:30 AM maxElectionId: null, Apr 21 01:12:30 AM maxSetVersion: null, Apr 21 01:12:30 AM commonWireVersion: 0, Apr 21 01:12:30 AM logicalSessionTimeoutMinutes: null Apr 21 01:12:30 AM }, Apr 21 01:12:30 AM code: undefined, Apr 21 01:12:30 AM [Symbol(errorLabels)]: Set(0) {} Apr 21 01:12:30 AM } Apr 21 01:12:30 AM (node:75) UnhandledPromiseRejectionWarning: MongooseServerSelectionError: getaddrinfo ENOTFOUND mongo Apr 21 01:12:30 AM at _handleConnectionErrors (/opt/render/project/src/node_modules/mongoose/lib/connection.js:755:11) Apr 21 01:12:30 AM at NativeConnection.openUri (/opt/render/project/src/node_modules/mongoose/lib/connection.js:730:11) Apr 21 01:12:30 AM (Use `node --trace-warnings ...` to show where the warning was created) Apr 21 01:12:30 AM (node:75) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1)
Dockerfile
FROM node WORKDIR /usr/src/app COPY package*.json ./ RUN npm install COPY . . EXPOSE 8080 CMD [ "node", "server.js" ]
docker-compose.yml
version: "3" services: web: build: . ports: - "8080:8080" external_links: - "mongo" mongo: container_name: mongo image: mongo volumes: - ./data:/data/db ports: - '27012:27017'
MongoDB连接代码
mongoose.connect('mongodb://mongo:27017/toDoBeta', { useNewUrlParser: true, })
解决建议
核心原因:Cloud Run是单容器部署环境,不支持Docker Compose的多容器服务发现机制。本地用
mongo作为主机名能生效,是因为Docker Compose的默认网络会自动解析服务名;但Cloud Run中没有这个DNS记录,所以无法解析地址。推荐方案:使用托管式MongoDB服务
- 创建MongoDB Atlas免费集群,获取包含用户名、密码的连接字符串
- 修改Node.js代码,通过环境变量读取连接字符串,避免硬编码:
const mongoUri = process.env.MONGODB_URI; mongoose.connect(mongoUri, { useNewUrlParser: true }); - 在Cloud Run部署配置中添加
MONGODB_URI环境变量,值为Atlas的连接字符串
备选方案:使用Google Cloud原生托管数据库
选择Cloud Memorystore for MongoDB(完全托管MongoDB),配置Cloud Run与该服务的VPC连接,之后在代码中使用实例的内部IP或域名进行连接。不推荐方案:将MongoDB与Node.js打包到同一容器
Cloud Run容器是无状态的,扩缩容会导致多实例数据不一致;且容器重启后数据会丢失,完全不适合运行MongoDB这类有状态数据库。
内容的提问来源于stack exchange,提问作者Andrei
相关产品推荐
相关产品推荐

