Docker部署Elixir API无法连接MongoDB容器问题求助
问题:Docker部署Elixir API无法连接MongoDB容器
我开发了一个基于Elixir的API,包含Users、Products、Orders模块,使用MongoDB 4.4。本地运行正常,但部署到Docker后始终无法连接另一个容器中的MongoDB,最终连接失败报错。我已经通过MongoDB Compass成功连接该MongoDB容器,推测是配置问题,但尝试了MongoDB容器IP、127.0.0.1、0.0.0.0、localhost等多种地址配置均无效。
错误日志
users_service-elixir_app-1 | 12:06:41.705 [error] Mongo.Protocol (#PID<0.566.0>) failed to connect: ** (Mongo.Error) localhost:27017 tcp connect: connection refused - :econnrefused users_service-elixir_app-1 | users_service-elixir_app-1 | 12:06:41.723 [notice] Application api_test exited: exited in: ApiTest.Application.start(:normal, []) users_service-elixir_app-1 | ** (EXIT) an exception was raised: users_service-elixir_app-1 | ** (MatchError) no match of right hand side value: {:error, :econnrefused} users_service-elixir_app-1 | (api_test 0.1.0) lib/services/publisher.ex:2: Api.Service.Publisher.start/2 users_service-elixir_app-1 | (kernel 9.0.1) application_master.erl:293: :application_master.start_it_old/4 users_service-elixir_app-1 | 12:06:41.722 [error] CRASH REPORT Process <0.456.0> with 0 neighbours exited with reason: no match of right hand value {error,econnrefused} in 'Elixir.Api.Service.Publisher':start/2 line 2 in application_master:init/4 line 142 users_service-elixir_app-1 | 12:06:41.723 [info] Application api_test exited with reason: no match of right hand value {error,econnrefused} in 'Elixir.Api.Service.Publisher':start/2 line 2 users_service-elixir_app-1 | Kernel pid terminated (application_controller) ({application_start_failure,api_test,{bad_return,{{'Elixir.ApiTest.Application',start,[normal,[]]},{'EXIT',{{badmatch,{error,econnrefused}},[{'Elixir.Api.Service.Publisher',start,2,[{file,"lib/services/publisher.ex"},{line,2}]},{application_master,start_it_old,4,[{file,"application_master.erl"},{line,293}]}]}}}}}) users_service-elixir_app-1 | users_service-elixir_app-1 | Crash dump is being written to: erl_crash.dump...done users_service-elixir_app-1 exited with code 1
相关配置文件
Dockerfile
FROM elixir:1.14 # Set environment variables ENV MIX_ENV=prod TERM=xterm # Create app directory and copy project files WORKDIR /app COPY . /app # Install hex package manager and rebar RUN mix local.hex --force && mix local.rebar --force # Install dependencies and compile the project RUN mix deps.get && mix deps.compile && mix compile # Expose the desired port (3000) EXPOSE 3000 # Start the server CMD ["mix", "run", "--no-halt"]
docker-compose.yml
version: '3' services: elixir_app: build: context: . dockerfile: Dockerfile ports: # Docker need to expose ports for you to access your app. - 3000:3000 depends_on: - mongodb - rabbitmq mongodb: image: mongo:4.4 container_name: mongodb restart: always environment: - MONGO_INITDB_ROOT_USERNAME=root - MONGO_INITDB_ROOT_PASSWORD=example ports: - 27017:27017 rabbitmq: image: rabbitmq:3-management container_name: rabbitmq environment: - RABBITMQ_DEFAULT_USER=guest - RABBITMQ_DEFAULT_PASS=guest ports: - 5672:5672 - 15672:15672
config.exs
use Mix.Config import_config "#{config_env()}.exs" # config :api_test, # api_host: "localhost", # api_port: 3000, # api_scheme: "http", # app_secret_key: "secret", # jwt_validity: 3600, # db_host: "localhost", # db_port: 27017, # db_db: "ski-online-shop", # db_tables: [ # "users" # ], # # routing_keys: %{ # # User Events # "user_login" => "api.login.auth-login.events", # "user_logout" => "api.login.auth-logout.events", # "user_register" => "api.login.auth-register.events", # # Order Events # "order_added" => "api.order.add.events", # "pay_order" => "api.order.pay.events", # # Invoice Events # "invoice_added" => "api.invoice.add.events" # }, # event_url: "guest:guest@localhost", # event_exchange: "my_api", # event_queue: "auth_service"
dev.exs 和 prod.exs(内容一致)
use Mix.Config config :users_service, port:3000 config :users_service, database: "ski-online-shop" config :users_service, pool_size: 2 config :users_service, :c, username: "user", password: "secret" config :users_service, :db_config, name: :mongo, url: "mongodb://mongodb:27017/ski-online-shop" config :amqp, connections: [ myconn: [url: "guest:guest@localhost"] ], channels: [ mychan: [connection: :myconn] ]
解决方案
1. 修复MongoDB认证不匹配问题
你的MongoDB容器配置了root账号和example密码,但Elixir配置中使用的是user和secret,账号密码不匹配会直接导致连接失败。修改dev.exs和prod.exs中的数据库配置,添加正确的认证信息:
config :users_service, :db_config, name: :mongo, url: "mongodb://root:example@mongodb:27017/ski-online-shop?authSource=admin"
2. 对齐配置模块与应用名称
错误日志显示应用是api_test,但你的配置都是针对users_service的,这说明应用实际读取的配置项和你定义的不匹配。检查Mongo连接代码,确保读取的配置键与配置文件一致:
- 如果连接代码是
Application.get_env(:api_test, :db_config),则将配置改为config :api_test, :db_config, ...
3. 确保MongoDB服务就绪后再启动Elixir应用
depends_on仅保证容器启动顺序,不保证MongoDB服务完全可用。添加健康检查确保服务就绪:
修改docker-compose.yml中的mongodb服务:
mongodb: image: mongo:4.4 container_name: mongodb restart: always environment: - MONGO_INITDB_ROOT_USERNAME=root - MONGO_INITDB_ROOT_PASSWORD=example ports: - 27017:27017 healthcheck: test: ["CMD", "mongo", "--eval", "db.adminCommand('ping')", "--username", "root", "--password", "example", "--authenticationDatabase", "admin"] interval: 5s timeout: 5s retries: 5
修改elixir_app服务的依赖条件:
elixir_app: build: context: . dockerfile: Dockerfile ports: - 3000:3000 depends_on: mongodb: condition: service_healthy rabbitmq: condition: service_started
4. 修复RabbitMQ连接地址
RabbitMQ配置中使用localhost无法在容器内访问,改为服务名rabbitmq:
config :amqp, connections: [ myconn: [url: "amqp://guest:guest@rabbitmq:5672"] ], channels: [ mychan: [connection: :myconn] ]
内容的提问来源于stack exchange,提问作者Alexandru-Dan Pop
相关产品推荐
相关产品推荐

