无法从 docker 将 RabbitMQ 连接到我的应用程序

Can't connect RabbitMQ to my app from docker

我目前被这个问题困扰了大约一个星期,真的找不到合适的解决方案。问题是,当我尝试连接到 dockerized RabbitMQ 时,它每次都会给我同样的错误:

wordofthedayapp-wordofthedayapp-1  | [40m[1m[33mwarn[39m[22m[49m: MassTransit[0]
wordofthedayapp-wordofthedayapp-1  |       Connection Failed: rabbitmq://localhost/
wordofthedayapp-wordofthedayapp-1  |       RabbitMQ.Client.Exceptions.BrokerUnreachableException: None of the specified endpoints were
 reachable
wordofthedayapp-wordofthedayapp-1  |        ---> System.AggregateException: One or more errors occurred. (Connection failed)
wordofthedayapp-wordofthedayapp-1  |        ---> RabbitMQ.Client.Exceptions.ConnectFailureException: Connection failed
wordofthedayapp-wordofthedayapp-1  |        ---> System.TimeoutException: The operation has timed out.
wordofthedayapp-wordofthedayapp-1  |          at RabbitMQ.Client.Impl.TaskExtensions.TimeoutAfter(Task task, TimeSpan timeout)
wordofthedayapp-wordofthedayapp-1  |          at RabbitMQ.Client.Impl.SocketFrameHandler.ConnectOrFail(ITcpClient socket, AmqpTcpEndpo
int endpoint, TimeSpan timeout)
wordofthedayapp-wordofthedayapp-1  |          --- End of inner exception stack trace ---
wordofthedayapp-wordofthedayapp-1  |          at RabbitMQ.Client.Impl.SocketFrameHandler.ConnectOrFail(ITcpClient socket, AmqpTcpEndpo
int endpoint, TimeSpan timeout)
wordofthedayapp-wordofthedayapp-1  |          at RabbitMQ.Client.Impl.SocketFrameHandler.ConnectUsingAddressFamily(AmqpTcpEndpoint end
point, Func`2 socketFactory, TimeSpan timeout, AddressFamily family)
wordofthedayapp-wordofthedayapp-1  |          at RabbitMQ.Client.Impl.SocketFrameHandler.ConnectUsingIPv4(AmqpTcpEndpoint endpoint, Fu
nc`2 socketFactory, TimeSpan timeout)
wordofthedayapp-wordofthedayapp-1  |          at RabbitMQ.Client.Impl.SocketFrameHandler..ctor(AmqpTcpEndpoint endpoint, Func`2 socket
Factory, TimeSpan connectionTimeout, TimeSpan readTimeout, TimeSpan writeTimeout)
wordofthedayapp-wordofthedayapp-1  |          at RabbitMQ.Client.Framing.Impl.IProtocolExtensions.CreateFrameHandler(IProtocol protoco
l, AmqpTcpEndpoint endpoint, Func`2 socketFactory, TimeSpan connectionTimeout, TimeSpan readTimeout, TimeSpan writeTimeout)
wordofthedayapp-wordofthedayapp-1  |          at RabbitMQ.Client.ConnectionFactory.CreateFrameHandler(AmqpTcpEndpoint endpoint)
wordofthedayapp-wordofthedayapp-1  |          at RabbitMQ.Client.EndpointResolverExtensions.SelectOne[T](IEndpointResolver resolver, F
unc`2 selector)
wordofthedayapp-wordofthedayapp-1  |          --- End of inner exception stack trace ---
wordofthedayapp-wordofthedayapp-1  |          at RabbitMQ.Client.EndpointResolverExtensions.SelectOne[T](IEndpointResolver resolver, F
unc`2 selector)
wordofthedayapp-wordofthedayapp-1  |          at RabbitMQ.Client.ConnectionFactory.CreateConnection(IEndpointResolver endpointResolver
, String clientProvidedName)
wordofthedayapp-wordofthedayapp-1  |          --- End of inner exception stack trace ---
wordofthedayapp-wordofthedayapp-1  |          at RabbitMQ.Client.ConnectionFactory.CreateConnection(IEndpointResolver endpointResolver
, String clientProvidedName)
wordofthedayapp-wordofthedayapp-1  |          at RabbitMQ.Client.ConnectionFactory.CreateConnection(IList`1 hostnames, String clientPr
ovidedName)
wordofthedayapp-wordofthedayapp-1  |          at MassTransit.RabbitMqTransport.Integration.ConnectionContextFactory.CreateConnection(I
Supervisor supervisor)

在这里你可以找到我的 docker-compose.yml:

version: '3.9'
services:
  rabbitmq:
    image: rabbitmq:3.9-management
    hostname: rabbitmq
    volumes:
      - "~/.docker-conf/rabbitmq/data/:/var/lib/rabbitmq/"
      - "~/.docker-conf/rabbitmq/log/:/var/log/rabbitmq"
    ports:
      - 5672:5672
      - 15672:15672
    expose:
     - 5672
     - 15672
    environment:
      - RABBITMQ_DEFAULT_USER=guest
      - RABBITMQ_DEFAULT_PASS=guest
    healthcheck:
        test: [ "CMD", "rabbitmqctl", "status", "-f", "http://localhost:15672"]
        interval: 5s
        timeout: 20s
        retries: 5
    networks:
      - app

  ms-sql-server:
    container_name: ms-sql-server
    image: mcr.microsoft.com/mssql/server:2019-latest
    user: root
    volumes:
      - "appdb:/var/opt/mssql/data"
    environment:
      ACCEPT_EULA: "Y"
      SA_PASSWORD: "Password123!"
      MSSQL_PID: Express
    ports:
      - 1433:1433
    healthcheck:
        test: ["CMD" ,"ping", "-h", "localhost"]
        timeout: 20s
        retries: 10
    networks:
      - app

  wordofthedayapp:
    build:
      dockerfile: WordOfTheDay.Api/Dockerfile
    image: wordofthedayapp
    environment:
      DbServer: "ms-sql-server"
      DbPort: "1433"
      DbUser: "sa"
      Password: "Password123!"
      Database: "appdb"
    ports:
      - 5001:80
    restart: on-failure
    depends_on:
      - rabbitmq
    networks:
      - app

volumes:
  appdb:

networks:
  app:

我的应用设置字符串:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*",
  "ConnectionStrings": {
    "WordContext": "Server=ms-sql-server;Database=master;User=sa;Password=Password123!;MultipleActiveResultSets=true;Integrated Security=false;TrustServerCertificate=true",
    "RabbitMQHost": "amqp://elias:123456@localhost:5672"
  }
}

这是它在使用 MassTransit 的应用程序中的工作方式:

public static void AddConfiguredMassTransit(this IServiceCollection services, string host)
        {
            services.AddMassTransit(Configuration =>
            {
                Configuration.UsingRabbitMq((context, config) =>
                {
                    config.Host(host);
                });
            });

            services.AddMassTransitHostedService();
        }
services.AddConfiguredMassTransit(Configuration.GetConnectionString("RabbitMQHost"));

我希望至少有人知道这段代码有什么问题,因为我真的很厌倦尝试修复它并浏览互联网寻找解决方案。提前致谢!

P.S。重要信息!当我在没有 docker 的情况下在本地测试它时一切正常,但是当我尝试 docker 化应用程序时发生了这种情况。

如果您在本地测试,主机很可能是 localhost,因为 Docker 将端口暴露给本地机器。但是,当 运行 在容器中时,虚拟网络的主机名应为 rabbitmq,当 运行 在容器中时,需要使用主机名而不是 localhost同一网络。

由于日志显示:

Connection Failed: rabbitmq://localhost/

我猜你在容器内 运行 时没有更新主机名。

您可以轻松确定您的应用程序是否 运行 在容器中:

bool IsRunningInContainer => bool.TryParse(Environment.GetEnvironmentVariable("DOTNET_RUNNING_IN_CONTAINER"), out var inDocker) && inDocker;

然后,在你的配置中:

var host = IsRunningInContainer ? "rabbitmq" : "localhost";