Connection refused on API request between containers with docker compose
but it doesn't when I do ping to serviceB's API REST:
root@serviceA_id:/app# ping -p 80 serviceb/api/bar PATTERN: 0x80 ping: serviceb/api/bar: Temporary failure in name resolution
That may be the cause of Connection Refused error when doing API requests from ASP.NET
That's not how ping works. Ping uses ICMP, not TCP, and not HTTP which works on top of TCP. You ping a host, not a TCP port or HTTP API. So the above is expected to fail.
I can also stablish connection with API REST endpoint with CURL but Content-Length recieved is 0
root@serviceA_id:/app# curl -v http://serviceb/api/bar * Trying 10.168.0.3... * TCP_NODELAY set * Connected to serviceb (10.168.0.3) port 80 (#0)
This indicates you have correctly configured docker containers to communicate, there's nothing more to debug in the configuration of your networks, and you know your serviceb is is listening.
The only things left to debug are:
- Make sure servicea is connecting to serviceb on port 80, not 65112 or any other host port. Containers communicate between each other on container ports.
- Make sure you are running the code posted, and not a previous version. This is easy to mistake when building and deploying images, especially if you aren't changing your image tag for each build.
- Make sure you give serviceb time to start. I've often seen these errors when servicea starts before serviceb.
If you still have issues, you can start debugging with tools like tcpdump. E.g.
docker run -it --rm --net container:$container_id \
nicolaka/netshoot tcpdump -i any port 80
Replace the $container_id
with the id of serviceb to see any TCP requests to port 80 on that container.
ServiceA's HTTP requests were being redirected (HTTP 307 status code) to https://serviceb:44359/api/bar
being :44359
the host port for HTTPS. Host ports are not accessible between containers, container ports do. So if I access to serviceA's terminal and send an HTTP request with curl
verbose -v
following redirections -L
to the URI http://serviceb/api/bar
I got the Connection Refused error:
root@serviceA_id:/app# curl -v -L http://serviceb/api/bar
* Trying 10.168.0.3...
* TCP_NODELAY set
* Connected to serviceb (10.168.0.3) port 80 (#0)
> GET /api/bar HTTP/1.1
> Host: serviceb
> User-Agent: curl/7.52.1
> Accept: */*
>
< HTTP/1.1 307 Temporary Redirect
< Date: Wed, 19 Jun 2019 08:48:33 GMT
< Server: Kestrel
< Content-Length: 0
< Location: https://serviceb:44359/api/bar
<
* Curl_http_done: called premature == 0
* Connection #0 to host serviceb left intact
* Issue another request to this URL: 'https://serviceb:44359/api/bar'
* Trying 10.168.0.3...
* TCP_NODELAY set
* connect to 10.168.0.3 port 44359 failed: Connection refused
* Failed to connect to serviceb port 44359: Connection refused
* Closing connection 1
curl: (7) Failed to connect to serviceb port 44359: Connection refused
Why I were being redirected to host port?
In Startup.cs
my services were using app.UseHttpsRedirection();
, that line was causing the problem.
The default configuration of HttpsPolicyBuilderExtensions.UseHttpsRedirection(IApplicationBuilder) method redirects to HTTPS host port by default. If you want to use a different port for redirection you need to add that option so Startup.cs
will look like this:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
...
services.AddHttpsRedirection(options =>
{
options.HttpsPort = 443;
});
...
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
...
app.UseHttpsRedirection();
...
}
}