我正在尝试设置一个简单的docker-compose文件,其中包括一个rabbitmq容器和一个连接到rabbitmq的简单express服务器。当我尝试从我的express应用程序连接到rabbitmq时,出现以下错误:
Error: connect ECONNREFUSED 172.19.0.2:5672
at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1247:16) {
errno: -111,
code: 'ECONNREFUSED',
syscall: 'connect',
address: '172.19.0.2',
port: 5672
}
我手动检查了docker网络的IP地址,以验证172.19.0.2确实是rabbitmq进程,确实如此。
这是我的 docker-compose:
version: '3'
services:
rabbitmq:
image: rabbitmq:3-management-alpine
container_name: 'rabbitmq'
environment:
- RABBITMQ_DEFAULT_USER=admin
- RABBITMQ_DEFAULT_PASS=pass
ports:
- 5672:5672
- 15672:15672
producerexpress:
build: ./service1
container_name: producerexpress
ports:
- 3000:3000
environment:
- PORT=3000
depends_on:
- rabbitmq
以及 Express 应用程序及其 docker 文件:
const express = require('express');
const app = express();
const port = process.env.PORT || 3000;
const amqp = require('amqplib');
const amqpUrl = process.env.AMQP_URL || 'amqp://admin:<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="c5b5a4b6b685f4f2f7ebf4fcebf5ebf7" rel="noreferrer noopener nofollow">[email protected]</a>:5672';
let channel;
let connection;
connect();
async function connect(){
try{
connection = await amqp.connect(amqpUrl);
channel = await connection.createChannel();
await channel.assertQueue('chatExchange', {durable: false});
} catch (err) {
console.log(err);
}
}
function sendRabbitMessage(msg) {
channel.sendToQueue('chatExchange', Buffer.from(msg));
}
app.get('/', (req, res) => {
let msg = 'Triggered by get request';
sendRabbitMessage(msg);
res.send('Sent rabbitmq message!');
});
app.listen(port, () => {
console.log(`Server started on port ${port}`);
} );
FROM node:16
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
ENV PORT=3000
ENV AMQP_URL=amqp://admin:<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="b4c4d5c7c7f48583869a858d9a849a86" rel="noreferrer noopener nofollow">[email protected]</a>:5672
EXPOSE 3000
CMD ["npm", "start"]
这是我第一次使用 docker compose,我在这里找到的所有修复似乎都表明我做的一切都是正确的。我错过了什么?
最佳答案
TL;DR
depends_on
保证服务启动的顺序,但这并不能保证它们启动的进程的任何内容。
在这些情况下,您应该展开 depends_on
按顺序声明to take into account the health status
感兴趣的过程
首先,您应该避免使 cointainers 的通信依赖于它们的 IP 地址,而是依赖于它们的服务名称,因为您使用的是 docker compose。
含义,而不是amqp://admin:<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="a5d5c4d6d6e59492978b949c8b958b97" rel="noreferrer noopener nofollow">[email protected]</a>:5672
您应该使用amqp://admin:pass@rabbitmq:5672
继续讨论核心问题,您的producerexpress
依赖rabbitmq
以便发挥作用。
因此,您添加了 depends_on
致producerexpress
的声明来解决这个问题。但这还不够,引用https://docs.docker.com/compose/startup-order/
You can control the order of service startup and shutdown with the depends_on option. Compose always starts and stops containers in dependency order, .... However,
for startup Compose does not wait until a container is “ready” (whatever that means for your particular application) - only until it’s running
.
因此,您需要添加 health check
为了保证rabbitmq process has started
成功,not just the container
.
为了实现这一目标,您应该更改您的 compose
文件
version: '3'
services:
rabbitmq:
build: ./rabbitmq
container_name: 'rabbitmq'
environment:
- RABBITMQ_DEFAULT_USER=admin
- RABBITMQ_DEFAULT_PASS=pass
ports:
- 5672:5672
- 15672:15672
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:15672"]
interval: 30s
timeout: 10s
retries: 5
producerexpress:
build: ./service1
restart: on-failure
container_name: producerexpress
ports:
- 3000:3000
environment:
- PORT=3000
depends_on:
rabbitmq:
condition: service_healthy
为了进行健康检查,我们需要 curl
打包到rabbitmq镜像中,所以添加以下Dockerfile
FROM rabbitmq:3-management-alpine
RUN apk update
RUN apk add curl
EXPOSE 5672 15672
最后,为了使此更改兼容,创建以下目录结构
./docker-compose.yml
./rabbitmq/
--- Dockerfile
./service1/
--- Dockerfile
关于node.js - docker 容器之间的 econnrefusedrabbitMQ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73588664/