I dabbled into .NET recently and after finishing the project I ended up with 2 microservices which were .NET projects under the same solution. It turns out that when dockerizing the microservices their build instructions are identical. The only difference is the command which needs to be invoked in order to start the microservice.
Below you can see a sample Dockerfile for a .NET application with multiple microservices:
FROM mcr.microsoft.com/dotnet/sdk:5.0 AS build WORKDIR /app # install necessary packages COPY *.sln . COPY MicroserviceA/*.csproj ./MicroserviceA/ COPY MicroserviceB/*.csproj ./MicroserviceB/ COPY Common/*.csproj ./Common/ RUN dotnet restore ./MySolution.sln # build executables of all projects/microservices COPY . ./ RUN dotnet publish -c Release -o out # Copy executables FROM mcr.microsoft.com/dotnet/aspnet:5.0 WORKDIR /app COPY --from=build /app/out . CMD ["dotnet", "MicroserviceA.dll"]
As you can see the
CMD directive invokes
MicroserviceA, but what about
MicroserviceB? Because all previous stages are the same for
MicroserviceB it’s redundant to have another Dockerfile dedicated just to
This means that executing
docker run myimage on the image built by the Dockerfile above will start
MicroserviceA by default. However, executing
docker run myimage dotnet MicroserviceB.dll will override the default
CMD and invoke
MicroserviceB instead. As a result the Dockerfile can be re-used for any microservice project in the .NET app.
An even cleaner solution is to use
command option in order to specify each microservice:
version: "3.9" services: microservicea: image: myimage/microservicea build: . command: ["dotnet", "MicroserviceA.dll"] microserviceb: image: myimage/microserviceb build: . command: ["dotnet", "MicroserviceB.dll"]
I hope the post shed some light on overriding Dockerfile default
CMD and on organizing your .NET apps!