Template repository showing how to be a good .NET application in a k8s cluster.
Below is a set of recommendations for being a good service. The recommendations are not tied to a specific language or framework.
- Configuration through environment variables.
- Expose readiness endpoint
- Expose endpoint that Prometheus can scrape
- Be stateless
- Support multiple instances
- Always be in a releasable state
- Automate build and deployment.
Some of above recommendations are heavily inspired by https://12factor.net/. It is recommended read https://12factor.net/ for more inspiration and further details. Some points go further than just being a good service and also touches areas like operations.
Below tools is required to work with the solution.
- EF Core for database migrations. Can be installed with
dotnet tool install --global dotnet-ef
- .NET 8.0
- Docker
- It is recommended to use Visual Studio 2022. Visual Studio Code can be used as well.
The service uses a few different NuGet packages out of the box.
- Serilog is used for logging - https://serilog.net/
- Swashbuckle is used for for two things - https://github.com/RicoSuter/NSwag
- Generating abstract controller classes based on OpenAPI specification
- Generating clients used in integration test.
- Entity Framework Core - https://learn.microsoft.com/en-us/ef/core/
- Pomelo.EntityFrameworkCore.MySql provides both MariaDB and MySQL driver for EF Core - https://github.com/PomeloFoundation/Pomelo.EntityFrameworkCore.MySql
- EF Core HealthChecks is used to provide EF Core health check probe - https://learn.microsoft.com/en-us/aspnet/core/host-and-deploy/health-checks?view=aspnetcore-7.0
- prometheus-net is used to generate Prometheus scrape endpoint - https://github.com/prometheus-net/prometheus-net
Click "Use this template" in Github. After new repository have been created clone the solution and run setup.sh
command. This will rename the most essential stuff in the solution. Finally open it in your favaroute IDE and rename solution, namespaces etc.
Models and interfaces is generated based on OpenAPI documentation. Currently generating models and interfaces is a manual task. It can be done with the below command. It is expected that you are placed in the solution folder.
docker run --rm --user $(id -u) -v $(pwd)/Documentation:/local openapitools/openapi-generator-cli generate -i /local/api.yaml -o /local/Generated -g aspnetcore -p buildTarget=library,returnICollection=true,aspnetCoreVersion=6.0,isLibrary=true,operationIsAsync=true,operationResultTask=true,nullableReferenceTypes=true,useNewtonsoft=true,useDateTimeOffset=true
or simply run below command.
./build/generate-models.sh
When the CI/CD pipeline is executed, the generation is done as a part of the pipeline to ensure that solution is using latest version of the API.
The service is listening for connections on port 8080.
Health endpoint is listening on port 8081. This is used for Prometheus scraping and health endpoints.
Prometheus scrape endpoint: http://localhost:8081/metrics
Health URL that can be used for readiness probe etc: http://localhost:8081/healthz
OpenAPI documentation is exposed through Swagger if the service is started in Development mode. This is done by settings the
environment variable ASPNETCORE_ENVIRONMENT
to Development
.
The service is using EF Core as database framework. Database migrations is handlded by the service during startup.
Detailed documentation and guide for EF core can be found at https://learn.microsoft.com/en-us/ef/core/.
When service is first created an initial migration must be created. It should created after initial model have been created.
Initial migration is done with the command dotnet ef migrations add InitialCreate
.
When a schema change is required a new migration must be added.
After the model have been changed in the code a new migration is added with the command dotnet ef migrations add <migration name>
. Consider naming your migration something meaningful.
Configuration is prefarably done through environment variables.
Environment variable | Description | Required |
---|---|---|
Serilog__MinimumLevel__Default | Default log level. Defaults to Information. | No |
ConnectionStrings__db | Database connection string. Example: server=db;user=hellouser;password=secret1234;database=hellodb |
Yes |
TEST_VAR | Variable used for demonstrating on how to use environment variables in the service. | Yes |