Reputation: 31
I am trying to build a microservice architecture system using Ocelot as my API Gateway. I have had the current problem for about 2 weeks and have not been able to figure out why it is happening, so I am turing to the experts and hopefully you can help :).
The structure at the moment is as follows: I have an AccountAPI and an Ocelot API Gateway. I have added the route from the API Gateway to the AccountAPI according to the docs. When I run the project, I can call the AccountAPI directly, and it works fine. But when I call through the API Gateway, I get this error.
Error Code: ConnectionToDownstreamServiceError Message: Error connecting to downstream service, exception:
System.Net.Http.HttpRequestException: No connection could be made because the target machine actively refused it.
(localhost:5101)
Quite obviously, it is not even reaching the controller of the AccountAPI, so I can't even debug >.>
The fact that I can access the object without going through the gateway tells me it is not a network / firewall issue (I turned off all my firewalls just to test, and got the same result).
This is what is in my ocelot.json file (which should connect Ocelot to the AccountAPI)
{
"GlobalConfiguration": {
"BaseUrl": "http://localhost:5111/"
},
"Routes": [
{
"DownstreamPathTemplate": "/Account/{url}",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "localhost",
"Port": 5101
}
],
"UpstreamPathTemplate": "/MeHealth/Account/{url}",
"UpstreamHttpMethod": [ "GET", "POST", "PUT", "DELETE" ],
"Priority": 1
}
]
}
So if I call https:// localhost:5101/Account/1
I get my correct object returned. But with calling https:// localhost:5111/MeHalth/Account/1
I get the error. (I did also try http://
(for those who caught the scheme) and I get the same result as https)).
Other things to note: Both of these are deployed through the docker-compose with the following config:
services:
ocelotapigateway:
environment:
- ASPNETCORE_ENVIRONMENT=Development
- ASPNETCORE_URLS=https://+:443;http://+:80
ports:
- "5111:443"
volumes:
- ${APPDATA}/Microsoft/UserSecrets:C:\Users\ContainerUser\AppData\Roaming\Microsoft\UserSecrets:ro
- ${APPDATA}/ASP.NET/Https:C:\Users\ContainerUser\AppData\Roaming\ASP.NET\Https:ro
accountapi:
environment:
- ASPNETCORE_ENVIRONMENT=Development
- ASPNETCORE_URLS=https://+:443;http://+:80
ports:
- "5101:443"
volumes:
- ${APPDATA}/Microsoft/UserSecrets:C:\Users\ContainerUser\AppData\Roaming\Microsoft\UserSecrets:ro
- ${APPDATA}/ASP.NET/Https:C:\Users\ContainerUser\AppData\Roaming\ASP.NET\Https:ro
Any advice or help that you can give will be greatly appreciated. Please also let me know if you need extra information on something.
Upvotes: 3
Views: 5542
Reputation: 666
Do not use https (and remove app.UseHttpsRedirection())
Use docker internal host name: "Host": "host.docker.internal"
Below is working example;
Ocelot.json
{
"Routes": [
{
"DownstreamPathTemplate": "/api/v1/{everything}",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "host.docker.internal",
"Port": 7001
}
],
"UpstreamPathTemplate": "/article-service/{everything}",
"UpstreamHttpMethod": [ "GET", "POST", "PUT", "DELETE" ]
},
{
"DownstreamPathTemplate": "/api/v1/{everything}",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "host.docker.internal",
"Port": 7002
}
],
"UpstreamPathTemplate": "/review-service/{everything}",
"UpstreamHttpMethod": [ "GET", "POST", "PUT", "DELETE" ]
}
],
"GlobalConfiguration": {
"BaseUrl": "http://localhost:7000"
}
}
docker-compose.yml
version: '3.4'
services:
data:
container_name: sqlserver
image: mcr.microsoft.com/mssql/server:2019-latest
environment:
- SA_PASSWORD=@P****
- ACCEPT_EULA=Y
ports:
- "1433:1433"
volumes:
- ./APPDATA:/var/opt/mssql/data
myapp.apigateway:
image: ${DOCKER_REGISTRY-}myappapigateway
build:
context: .
dockerfile: MyApp.ApiGateway/Dockerfile
ports:
- "7000:80"
myapp.articleservice:
image: ${DOCKER_REGISTRY-}myapparticleservice
build:
context: .
dockerfile: MyApp.ArticleService/Dockerfile
ports:
- "7001:80"
myapp.reviewservice:
image: ${DOCKER_REGISTRY-}myappreviewservice
build:
context: .
dockerfile: MyApp.ReviewService/Dockerfile
ports:
- "7002:80"
docker-compose.override.yml
version: '3.4'
services:
myapp.apigateway:
environment:
- ASPNETCORE_ENVIRONMENT=Development
- ASPNETCORE_URLS=https://+:443;http://+:80
ports:
- "80"
- "443"
volumes:
- ${APPDATA}/Microsoft/UserSecrets:/root/.microsoft/usersecrets:ro
- ${APPDATA}/ASP.NET/Https:/root/.aspnet/https:ro
myapp.reviewservice:
environment:
- ASPNETCORE_ENVIRONMENT=Development
- ASPNETCORE_URLS=https://+:443;http://+:80
ports:
- "80"
- "443"
volumes:
- ${APPDATA}/Microsoft/UserSecrets:/root/.microsoft/usersecrets:ro
- ${APPDATA}/ASP.NET/Https:/root/.aspnet/https:ro
myapp.articleservice:
environment:
- ASPNETCORE_ENVIRONMENT=Development
- ASPNETCORE_URLS=https://+:443;http://+:80
ports:
- "80"
- "443"
volumes:
- ${APPDATA}/Microsoft/UserSecrets:/root/.microsoft/usersecrets:ro
- ${APPDATA}/ASP.NET/Https:/root/.aspnet/https:ro
Upvotes: 1
Reputation: 666
I also trapped in the same problem just only need to commented out in API's startup file
app.UseHttpsRedirection();
and in ocelot file
"Host": "host.docker.internal",
"Port": 5101
OR
"Host": "service-name",
"Port": 80
Upvotes: 0
Reputation: 5532
The problem is localhost
on your host machine is not same as localhost
when running in docker container. Think about docker as isolated "virtual machine" with its own localhost
. When your api gateway tries to reach localhost:5101
it fails because it not exists in this "virtual machine", it's running on your host machine. You have 2 solutions here:
host.docker.internal
and external port instead of localhost
: https://host.docker.internal:5101
.https://accountapi:443
Upvotes: 3