Containerizing gRPC Service

Introduction 

 
In past articles, we have seen how we can develop the gRPC service. In this article, let's check how we can run gRPC service in a docker container. If you haven't read about the gRPC service and its basics, I suggest you go through the following articles:
In this article, let's try to explore how we can run our gRPC service in Docker. Let's check the below steps to achieve that:
 

Add a gRPC service

 
We have seen how to add the gRPC service in the previous articles, but this time, let's change the way we add a gRPC service:
 
Containerizing gRPC Service
 
Here while adding the gRPC service, let's just enable Docker support, which will add the basic support to run our service in the docker.
 
Once we have added the project, you will see the following project structure:
 
Containerizing gRPC Service
 
We can see the Docker file is added with the project.
 
Docker File
 
Once we are done with adding the service, let's try to dissect the Docker file.
  1. FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-buster-slim AS runtime  
  2. WORKDIR /myworkingdirectory  
  3. EXPOSE 443  
  4. EXPOSE 80  
  5.   
  6. FROM mcr.microsoft.com/dotnet/core/sdk:3.1-buster AS build  
  7. WORKDIR /src  
  8. COPY ["GRPCDocker.csproj"""]  
  9. RUN dotnet restore "./GRPCDocker.csproj"  
  10. COPY . .  
  11. WORKDIR "/src/."  
  12. RUN dotnet build "GRPCDocker.csproj" -c Release -o /app/build  
  13.   
  14. FROM build AS publish  
  15. RUN dotnet publish "GRPCDocker.csproj" -c Release -o /app/publish  
  16.   
  17. FROM base AS final  
  18. WORKDIR /myworkingdirectory  
  19. COPY --from=publish /app/publish .  
  20. ENTRYPOINT ["dotnet""GRPCDocker.dll"]  
Generally, Docker is built around the concept of image layers every layer builds on the previous layer after adding dependencies, package, and runtime. Finally, the image produced contains everything right from your compiled application and then the things needed to run that application.
 
If we see the above Docker file, we see two images we are using in the application first one being the aspnet:3.1-buster-slim and another is SDK:3.1-buster out of this first image aspnet:3.1-buster-slim is used to run the application, and the second image sdk:3.1-buster is used for the compiling publishing the application.
 

Docker stages

 
Generally, the docker file is divided into the stages each stage starts from ‘FROM AS’ so if we look at our docker file we can see we have 4 stages in order to get our service up and running in the docker let’s see the stages.
 
Stage 1 - Set run time working directory and ports
  1. FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-buster-slim AS runtime  
  2. WORKDIR /myworkingdirectory  
  3. EXPOSE 443  
  4. EXPOSE 80  
In this stage, we are setting up the run time. Here in our case, we are setting it to .NET Core 3.1, then we are setting up the working directory and exposing the ports 443 and 80 of the docker.
 
Stage 2 - Build, Restore and copy
  1. FROM mcr.microsoft.com/dotnet/core/sdk:3.1-buster AS build  
  2. WORKDIR /src  
  3. COPY ["GRPCDocker.csproj"""]  
  4. RUN dotnet restore "./GRPCDocker.csproj"  
  5. COPY . .  
  6. WORKDIR "/src/."  
  7. RUN dotnet build "GRPCDocker.csproj" -c Release -o /app/build  
In this stage, what we do is we use the image SDK:3.1-buster which is an SDK image. Here, we run the dotnet restore command which basically restores .NET packages then we build the project using the dotnet build command.

Stage 3 - Publish the App
  1. FROM build AS publish  
  2. RUN dotnet publish "GRPCDocker.csproj" -c Release -o /app/publish 
This step created a publishable version of our service.
 
Stage 4 - final 
  1. FROM base AS final  
  2. WORKDIR /myworkingdirectory  
  3. COPY --from=publish /app/publish .  
  4. ENTRYPOINT ["dotnet""GRPCDocker.dll"]
This step copies the published version of the app to the base stage which we have created at the start of the app here we copy the stuff from the publish stage and app/publish folder to the working directory.
 
Docker Build
 
We have seen all the docker stages, now let's check how to build the image. The command that we use to build the image is as follows:
 
docker build -t grpcdocker .
 
In this, -t provides the name of the image, and the '.' at the end of the command tells to use the current folder as the context.
 
To build this, open our solution folder at the command prompt and just run this command on the command prompt you will be able to see the following outputs
 
Containerizing gRPC Service
 
Now that the image has been built, it's time to run the container
 

Run the Container

 
To run the container, we are going to use the following command:
 
docker run -d -p 5000:443 --name grpcdockerservice grpcdocker
 
In this command:
  1. -d : specifies the detached mode means the command this means the command won't block the command prompt and it will return to the command prompt
  2. -p : specifies port it maps the port of host computer 5000 to the docker port 443 so whenever the traffic hits the localhost:5000 it will forward it to the docker port 443
  3. –name : specifies the name of the docker container
  4. The final parameter is the image that we have built in the previous step.
Once we run the command, we get the following output:
 
Containerizing gRPC Service
 
The output string that we got is the docker container ID which will be a unique ID.
 
To see if the docker is running, run the following command which lists all the docker containers running in the host machine:
 
Containerizing gRPC Service
 
It will show the status of the application running which we have created just a minute ago.
 
This was about running gRPC service in the docker. In the next article, let's see how to consume the service in the client application.
 
You can find the source code for the above article available here.
 
References
  1. https://marcroussy.com/2020/05/01/docker-build-process-for-dotnet/
  2. https://marcroussy.com/2020/05/01/docker-build-process-for-dotnet/
  3. https://docs.microsoft.com/en-us/dotnet/architecture/grpc-for-wcf-developers/docker