We have a WPF application that will call a Web API called API-1 which is running in a docker container. I also have another API called API-2 which is also running in a docker but a different container.
Whenever the API-1 call happened from the application, the API-1 will do some logic and try to do a post request to API-2.
Now, my problem is, the post request to API-2 always returns Cannot assign requested address (localhost:XXXX).
If I try without docker, it works fine.
Also, a separate request to each of the API works fine (using POSTMAN)
This problem occurs only if the API deployed in the docker. I was using docker-compose to create the containers. I have created a docker network bridge and allocated it to the respective APIs in the docker-compose.yml file.
Here is my docker-compose file as well as the docker file for both of the APIs.
Docker-Compose.yml
version: "3.7"
networks :
localdev:
name: localdev
external: true
services:
api-01:
build:
context: .
dockerfile: api-01/Dockerfile
restart: always
container_name: "api-01"
ports:
- "8082:80"
environment:
ASPNETCORE_ENVIRONMENT: "Development"
networks:
- localdev
api-02:
build:
context: .
dockerfile: api-02/Dockerfile
restart: always
container_name: "api-02"
ports:
- "8083:80"
environment:
ASPNETCORE_ENVIRONMENT: "Development"
networks:
- localdev
DockerFile(API-1)
FROM mcr.microsoft.com/dotnet/aspnet:5.0-buster-slim AS base
WORKDIR /app
EXPOSE 80
FROM mcr.microsoft.com/dotnet/sdk:5.0-buster-slim AS build
WORKDIR /src
COPY ["api-01/api-01.csproj", "api-01/"]
COPY ["CommonEntities/CommonEntities.csproj", "CommonEntities/"]
RUN dotnet restore "api-01/api-01.csproj"
COPY . .
WORKDIR "/src/api-01"
RUN dotnet build "api-01.csproj" -c Release -o /app/build
FROM build AS publish
RUN dotnet publish "api-01.csproj" -c Release -o /app/publish
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "api-01.dll"]
DockerFile(API-2)
FROM mcr.microsoft.com/dotnet/aspnet:5.0-buster-slim AS base
WORKDIR /app
EXPOSE 80
FROM mcr.microsoft.com/dotnet/sdk:5.0-buster-slim AS build
WORKDIR /src
COPY ["api-02/api-02.csproj", "api-02/"]
COPY ["CommonEntities/CommonEntities.csproj", "CommonEntities/"]
RUN dotnet restore "api-02/api-02.csproj"
COPY . .
WORKDIR "/src/api-02"
RUN dotnet build "api-02.csproj" -c Release -o /app/build
FROM build AS publish
RUN dotnet publish "api-02.csproj" -c Release -o /app/publish
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "api-02.dll"]
I'm not sure what I'm missing here!
I have tried most of the solutions from the internet, but nothing works.
It looks like I need to use {DOCKER_IP} instead of "localhost" if I want to have communication between two API in two different containers.
After I changed my post request to hit "http://{My_PC_IP_Address}:8082", the request was successful.
Thanks to David for redirecting me to the right documentation https://docs.docker.com/network/bridge/
Related
I'm trying to containerize a .NET6 WebApi with a postgrescontainer. I have this Docker file to build the web api image:
#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging.
FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
WORKDIR /src
COPY ["MicroserviceTemplateDDD.csproj", "MicroserviceTemplateDDD/"]
RUN dotnet restore "MicroserviceTemplateDDD/MicroserviceTemplateDDD.csproj"
WORKDIR "/src/MicroserviceTemplateDDD"
COPY . .
RUN dotnet build "MicroserviceTemplateDDD.csproj" -c Release -o /app/build
FROM build AS publish
RUN dotnet publish "MicroserviceTemplateDDD.csproj" -c Release -o /app/publish
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
WORKDIR /app/publish
ENTRYPOINT ["dotnet", "MicroserviceTemplateDDD.dll"]
This runs successfully. But when i run docker-compose up to start the postgre and webapi container i get this error:
microservicetemplateddd_service1 | Process terminated. Couldn't find a valid ICU package installed on the system. Please install libicu using your package manager and try again. Alternatively you can set the configuration flag System.Globalization.Invariant to true if you want to run with no globalization support. Please see https://aka.ms/dotnet-missing-libicu for more information.
My docker compose:
version: "3.7"
services:
api:
image: microservicetemplateddd_service1
container_name: microservicetemplateddd_service1
restart: always
build:
context: .
dockerfile: Dockerfile
environment:
- ConnectionStrings:Context=Server=MicroserviceTemplateDDD_Service1_database;Database=Database;User Id=pa;Password=P4ssW0rd!;
- DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=false
depends_on:
- database
networks:
- network
ports:
- 8090:80
database:
image: postgres
container_name: microservicetemplateddd_service1_database
restart: always
environment:
- ACCEPT_EULA=Y
- POSTGRES_PASSWORD=P4ssW0rd!
- POSTGRES_USER=pa
networks:
- network
ports:
- 1433:1433
volumes:
- database:/var/opt/mssql
networks:
network:
volumes:
database:
I already tried to use other ms images like alpine and change the place of setting the env.
Per the docs, you should set the environment variable to 1 to disable globalization. Like this
environment:
- ConnectionStrings:Context=Server=MicroserviceTemplateDDD_Service1_database;Database=Database;User Id=pa;Password=P4ssW0rd!;
- DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=1
Since you always need to set it to run your container, it'll be a good idea to put the configuration into the image. You can put it at the beginning of the dockerfile and remove it from the docker-compose file
FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base
ENV DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=1
WORKDIR /app
EXPOSE 80
EXPOSE 443
That way you can't forget to set it and have the error pop up again.
I had a similar issue and got around it by adding this condition in the csproj
<ItemGroup Condition="$([MSBuild]::IsOSPlatform('Windows'))">
<RuntimeHostConfigurationOption Include="System.Globalization.AppLocalIcu" Value="68.2" />
</ItemGroup>
I have 3 docker images; rabbitmq, client and publisher image. Without using the docker images the three services communicate well on the default port 5672.
Below is my docker-compose.yml
version: '3.4'
services:
rabbitmq.messageclient:
image: ${DOCKER_REGISTRY-}rabbitmqmessageclient
ports:
- "5672"
build:
context: .
dockerfile: RabbitMQ.Client/Dockerfile
rabbitmq.producer:
image: ${DOCKER_REGISTRY-}rabbitmqproducer
ports:
- "5672"
build:
context: .
dockerfile: RabbitMQ.Producer/Dockerfile
rabbitmq:
image: rabbitmq:3-management
container_name: 'rabbitmq'
ports:
- 5672:5672
- 15672:15672
volumes:
- ~/.docker-conf/rabbitmq/data/:/var/lib/rabbitmq/mnesia
- ~/.docker-conf/rabbitmq/log/:/var/log/rabbitmq
networks:
- rabbitmq_go_net
networks:
rabbitmq_go_net:
driver: bridge
my Client
#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging.
FROM mcr.microsoft.com/dotnet/runtime:5.0 AS base
WORKDIR /app
FROM mcr.microsoft.com/dotnet/sdk:5.0 AS build
WORKDIR /src
COPY ["RabbitMQ.Client/RabbitMQ.MessageClient.csproj", "RabbitMQ.Client/"]
RUN dotnet restore "RabbitMQ.Client/RabbitMQ.MessageClient.csproj"
COPY . .
WORKDIR "/src/RabbitMQ.Client"
RUN dotnet build "RabbitMQ.MessageClient.csproj" -c Release -o /app/build
FROM build AS publish
RUN dotnet publish "RabbitMQ.MessageClient.csproj" -c Release -o /app/publish
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "RabbitMQ.MessageClient.dll"]
my Producer
#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging.
FROM mcr.microsoft.com/dotnet/runtime:5.0 AS base
WORKDIR /app
FROM mcr.microsoft.com/dotnet/sdk:5.0 AS build
WORKDIR /src
COPY ["RabbitMQ.Producer/RabbitMQ.Producer.csproj", "RabbitMQ.Producer/"]
RUN dotnet restore "RabbitMQ.Producer/RabbitMQ.Producer.csproj"
COPY . .
WORKDIR "/src/RabbitMQ.Producer"
RUN dotnet build "RabbitMQ.Producer.csproj" -c Release -o /app/build
FROM build AS publish
RUN dotnet publish "RabbitMQ.Producer.csproj" -c Release -o /app/publish
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "RabbitMQ.Producer.dll"]
My hostname is : localhost
I am unable to send and receive data between the rabbitmq.messageclient and the rabbitmq.producer service. What am I missing?
In short, each container behaves like an isolated machine, localhost in a container refers to its local network. Communication between two containers is the same as communication between two machines with respective IP addresses. docker-compose creates a bridged network for all containers by default so you can use containers' name to connect to them, and Docker internally do the address translation for you.
Not sure why you create a new bridge called rabbitmq_go_net but connect only rabbitmq to it. You may delete the network or add another two container to it as well. Then in your rabbitmq.messageclient container, you may connect the rabbitmq container using rabbitmq:5672 instead of localhost:5672, and so on.
References for docket compose network:
https://docs.docker.com/compose/networking/
https://docs.docker.com/compose/compose-file/compose-file-v3/#network
If you want to communicate with services inside your compose file, you should use service name as hostname. Also, "ports" section used for mapping ports to the host machine, you don't need it to connect between services.
I am trying to use docker-compose with my project.
Having issue with .Net 5 API project.
It works properly with ISS Express and Docker but when I run project with docker-compose api project is not working as expected.
As expeced when running docker-compose it should run API project and launch swagger api page instead it’s displaying different erros when exposed ports are accessed via browser. Please find attached snaps below.
Docker container image
browser run1
browser run2
browser run3
As you can see for each url it's displaying different error message in browser.
Following solutions to resolve issues but none worked.
1. Expose ports using below in docker file
ports:
- 51850:80
Docker expose ports
2. Try with debug environment
ARG BUILD_CONFIGURATION=Debug
ENV ASPNETCORE_ENVIRONMENT=Development
ENV DOTNET_USE_POLLING_FILE_WATCHER=true
ENV ASPNETCORE_URLS=http://+:80
stackoverlow suggestion - set environment to debug
3. Tried using VSCode docker-compose and Visual Studio docker-compose
Regenerated docker-compose file with help of Visual Studio and VS Code.
4. Tried setting up specific ports on Launchsettings.json
Tried settings specif ports with docker in launsettings.json
and exporting from docker, docker compose
Docker
FROM mcr.microsoft.com/dotnet/aspnet:5.0 AS base
WORKDIR /app
EXPOSE 44370
FROM mcr.microsoft.com/dotnet/sdk:5.0 AS build
WORKDIR /src
COPY ["TAPI/TAPI.csproj", "TAPI/"]
RUN dotnet restore "TAPI/TAPI.csproj"
COPY . .
WORKDIR "/src/TAPI"
RUN dotnet build "TAPI.csproj" -c Release -o /app/build
FROM build AS publish
RUN dotnet publish "TAPI.csproj" -c Release -o /app/publish
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "TAPI.dll"]
docker-compose
version: '3.4'
services:
todoworker:
image: tworker
build:
context: .
dockerfile: TWorker/Dockerfile
todoapi:
image: tapi
build:
context: .
dockerfile: TAPI/Dockerfile
ports:
- 80
- 443
- 44370
tangular:
image: tangular
build:
context: .
dockerfile: TAngular/Dockerfile
ports:
- 4200:4200
5. Tried with deleting all containers
Tried deleting all containers, images and recreating all after restarting docker desktop (using docker on windows system)
As suggested in following article Docker for clean build of an image
docker system prune
Docker desktop image
Even deleting images and containers from docker and recreating images some time it displayes image created time from past hours.
Date: 20-May-2021:
I have created another small Sample with two Web APIs. Tested on my local Laptop. Please get that to your local box and execute. Please let me know if you need any further assistance.
GitHub URL: https://github.com/vishipayyallore/mini-projects-2021/tree/master/Projects/CollegeDockerDemo
College.WebAPI Docker File
#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging.
FROM mcr.microsoft.com/dotnet/aspnet:5.0 AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443
FROM mcr.microsoft.com/dotnet/sdk:5.0 AS build
WORKDIR /src
COPY ["Source/College.WebAPI/College.WebAPI.csproj", "Source/College.WebAPI/"]
RUN dotnet restore "Source/College.WebAPI/College.WebAPI.csproj"
COPY . .
WORKDIR "/src/Source/College.WebAPI"
RUN dotnet build "College.WebAPI.csproj" -c Release -o /app/build
FROM build AS publish
RUN dotnet publish "College.WebAPI.csproj" -c Release -o /app/publish
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "College.WebAPI.dll"]
ToDo.WebAPI Docker File
#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging.
FROM mcr.microsoft.com/dotnet/aspnet:5.0 AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443
FROM mcr.microsoft.com/dotnet/sdk:5.0 AS build
WORKDIR /src
COPY ["Source/ToDo.WebAPI/ToDo.WebAPI.csproj", "Source/ToDo.WebAPI/"]
RUN dotnet restore "Source/ToDo.WebAPI/ToDo.WebAPI.csproj"
COPY . .
WORKDIR "/src/Source/ToDo.WebAPI"
RUN dotnet build "ToDo.WebAPI.csproj" -c Release -o /app/build
FROM build AS publish
RUN dotnet publish "ToDo.WebAPI.csproj" -c Release -o /app/publish
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "ToDo.WebAPI.dll"]
docker-compose.yml File
version: '3.4'
services:
college.webapi:
image: ${DOCKER_REGISTRY-}collegewebapi
build:
context: .
dockerfile: Source/College.WebAPI/Dockerfile
todo.webapi:
image: ${DOCKER_REGISTRY-}todowebapi
build:
context: .
dockerfile: Source/ToDo.WebAPI/Dockerfile
docker-compose.override.yml File
version: '3.4'
services:
college.webapi:
environment:
- ASPNETCORE_ENVIRONMENT=Development
ports:
- "8000:80"
volumes:
- ${APPDATA}/Microsoft/UserSecrets:/root/.microsoft/usersecrets:ro
- ${APPDATA}/ASP.NET/Https:/root/.aspnet/https:ro
todo.webapi:
environment:
- ASPNETCORE_ENVIRONMENT=Development
ports:
- "8001:80"
volumes:
- ${APPDATA}/Microsoft/UserSecrets:/root/.microsoft/usersecrets:ro
- ${APPDATA}/ASP.NET/Https:/root/.aspnet/https:ro
I was asked to create a .net solution with a web api and a console program, then have this available with a docker-compose command that includes the full environment. The web api is using mongodb and easynetq. The console program references the web api project and also uses easynetq. I know Visual Studio can provide me a dockerfile for each project. How do I proceed after this? Do I combine the 2 dockerfiles into 1 at the solution level? Or can I continue with the 2 dockerfiles?
Dockerfile for console program
FROM microsoft/dotnet:sdk AS build-env
WORKDIR /app
COPY . ./
RUN dotnet restore "./ConsoleProgram.csproj"
RUN dotnet publish "ConsoleProgram.csproj" -c Release -o out
FROM microsoft/dotnet:aspnetcore-runtime
WORKDIR /app
COPY --from=build-env /app/out .
ENTRYPOINT ["dotnet", "ConsoleProgram.dll"]
Dockerfile for webapi is identical as above, only names are changed
Docker compose at solution level
version: '3'
services:
mongo:
image: mongo
restart: always
ports:
- 27017:27017
webapi:
build: ./webapi
restart: always
ports:
- 5000:80
environment:
MongoDB__Host: mongo
depends_on:
- mongo
console:
build: ./console
restart: always
depends_on:
- webapi
After doing a docker compose on this I get the following errors:
Skipping project "C:\WebApi\WebApi.csproj" because it was not found.
The referenced project '..\WebApi\WebApi.csproj' does not exist.
Service 'console' failed to build: The command 'cmd /S /C dotnet
publish "Console.csproj" -c Release -o out' returned a non-zero code:
1
You are on the right way. You should have Dockerfile for each projects (in root of the project folder), then one file docker-compose.yaml and many docker-compose.override.yaml if you need.
There are some gaps in Dockerfile.
1.Don't copy COPY . ./ all files in ConsoleProgram image, first just copy csproj
COPY console/ConsoleProgram.csproj console/
2.After copy csproj file run dotnet restore to improve image building time
RUN dotnet restore console/ConsoleProgram.csproj
3.Then copy all other files and run dotnet publish (or build) with flag --no-restore
COPY console/ console/
RUN dotnet publish console/ConsoleProgram.csproj --no-restore -c Release -o /out
Here are some example how Dockerfile should look
FROM microsoft/dotnet:2.2-sdk AS publish
WORKDIR /src
COPY console/ConsoleProgram.csproj console/
RUN dotnet restore console/ConsoleProgram.csproj
COPY console/ console/
RUN dotnet publish console/ConsoleProgram.csproj --no-restore -c Release -o /app
FROM microsoft/dotnet:2.2-aspnetcore-runtime AS runtime
WORKDIR /app
COPY --from=publish /app .
ENTRYPOINT ["dotnet", "ConsoleProgram.dll"]
Something similar should be for WebAPI. Now look at your docker-compose.yaml. You should specify build context and image name
webapi:
image: 'webapi'
build:
context: .
dockerfile: ./webapi/Dockerfile
restart: always
ports:
- 5000:80
environment:
MongoDB__Host: mongo
depends_on:
- mongo
console:
image: 'console'
build:
context: .
dockerfile: ./console/Dockerfile
restart: always
depends_on:
- webapi
As I doesn't know your project structure you need to be careful with all paths to project in this answer
I am a little confused as to how all of this works as this is my first time playing with Docker.
I've downloaded the following docker image of Microsoft SQL Server Express (https://hub.docker.com/r/microsoft/mssql-server-windows-express/).
I am trying to docker-compose together some existing containers and every time I run docker-compose up, what I want to have happen is that a new database is created and a target container is run.
Here is the existing Dockerfile for the container that I want to have execute. "Execute this" is the container that I want to have dotnet run run on and any "HelperService" are services that should be up before the target container is run:
FROM microsoft/dotnet:2.0-runtime-nanoserver-1709 AS base
WORKDIR /app
FROM microsoft/dotnet:2.0-sdk-nanoserver-1709 AS build
WORKDIR /src
COPY ExecuteThis/ExecuteThis.csproj ExecuteThis/
COPY ../HelperService/HelperService.csproj ../HelperService/
COPY ../HelperService2/HelperService2.csproj ../HelperService2/
COPY ../HelperService3/HelperService3.csproj ../HelperService3/
COPY ../HelperService4/HelperService4.csproj ../HelperService4/
COPY ../HelperService5/HelperService5.csproj ../HelperService5/
COPY ../HelperService6/HelperService6.csproj ../HelperService6/
RUN dotnet restore ExecuteThis/ExecuteThis.csproj
COPY . .
WORKDIR /src/ExecuteThis
RUN dotnet build ExecuteThis.csproj -c Release -o /app
FROM build AS publish
RUN dotnet publish ExecutThis.csproj -c Release -o /app
FROM base AS final
WORKDIR /app
COPY --from=publish /app .
ENTRYPOINT ["dotnet", "ExecuteThis.dll"]
Here is a docker-compose.yml file:
version: '3.4'
services:
sqlserver:
image: microsoft/mssql-server-windows-express
helperservice:
image: helperservice
helperservice2:
image: helperservice2
helperservice3:
image: helperservice3
helperservice4:
image: helperservice4
helperservice5:
image: helperservice5
helperservice6:
image: helperservice6
executethis:
image: ${DOCKER_REGISTRY}executethis
depends_on:
- sqlserver
- helperservice
- helperservice2
- helperservice3
- helperservice4
- helperservice5
- helperservice6
build:
context: .
dockerfile: ExecuteThis\Dockerfile
My question is: how do I generate a database and where should I write those instructions? How do I dotnet run my "ExecuteThis" container?