Docker化Rails 5.1.5连接ELK栈Logstash报Errno::EADDRNOTAVAIL错误求助
Hey Jose, let's break down why you're hitting that Errno::EADDRNOTAVAIL error and fix it step by step. The core issue here is how Docker handles network isolation—your Rails container's localhost isn't pointing to your Logstash container, which is a super common gotcha when working with multi-container setups.
1. Understand the Network Isolation Problem
Every Docker container runs in its own network namespace. When your Rails app tries to connect to localhost:5228, it's trying to reach the Rails container itself, not the Logstash container running alongside it. That's why you get the "Cannot assign requested address" error—there's no service listening on port 5228 inside the Rails container.
2. Fix the Network Setup
First, make sure your Rails and ELK containers are on the same Docker network. This lets them communicate using container/service names instead of localhost.
Option A: Using Docker Compose (Recommended)
If you're using docker-compose.yml, Docker automatically creates a dedicated network for your services. Just reference the Logstash service name in your Rails config. For example, if your ELK compose file defines a service named logstash, your Rails app should target logstash:5228 instead of localhost:5228.
Option B: Manual Network Creation
If you're running containers individually, create a shared network and attach both containers to it:
# Create a shared network docker network create elk-rails-network # Start Logstash attached to the network docker run --network elk-rails-network --name logstash [your-logstash-image] # Start Rails attached to the same network docker run --network elk-rails-network [your-rails-image]
Now your Rails app can connect to logstash:5228 (using the container name logstash).
3. Verify Logstash's Listening Configuration
Make sure Logstash is configured to accept connections from outside its own container. Check your Logstash input config (usually logstash.conf) and ensure the TCP input binds to 0.0.0.0 (not localhost):
input { tcp { port => 5228 host => "0.0.0.0" # This allows connections from any network interface codec => json_lines # Match the codec your Rails logger uses } }
If Logstash is only bound to localhost, it won't accept connections from other containers.
4. Update Your Rails LogStashLogger Config
Update your Rails configuration to use the Logstash container/service name instead of localhost. You can do this directly in config/application.rb or per-environment files (like config/environments/production.rb):
config.logstash.host = ENV["LOGSTASH_HOST"] || "logstash" config.logstash.port = ENV["LOGSTASH_PORT"] || 5228
Using environment variables makes this flexible—you can set LOGSTASH_HOST in your docker-compose.yml for Rails:
services: rails: environment: - LOGSTASH_HOST=logstash - LOGSTASH_PORT=5228
5. Test Connectivity
To debug further, jump into your Rails container and test if it can reach Logstash:
# Ping the Logstash service/container to confirm DNS resolution docker exec -it [your-rails-container-name] ping logstash # Test if the port is open with telnet docker exec -it [your-rails-container-name] telnet logstash 5228
If ping works but telnet fails, check Logstash's logs to ensure it started correctly:
docker logs logstash
Look for errors about the TCP input plugin failing to load or bind to the port.
6. Bonus: Ensure Logstash is Ready Before Rails
If you're using Docker Compose, add health checks to make sure Rails waits until Logstash is fully operational:
services: logstash: healthcheck: test: ["CMD", "curl", "-f", "http://localhost:9600"] # Logstash's monitoring API interval: 10s timeout: 5s retries: 5 rails: depends_on: logstash: condition: service_healthy
This prevents Rails from trying to connect before Logstash is ready to accept connections.
内容的提问来源于stack exchange,提问作者Jose A

