Distributed Tracing in ASP.NET Core With Jaeger and Tye, Part 2: Project Tye
Tye is an experimental dotnet tool from Microsoft that aims to make developing, testing, and deploying microservices easier.
Join the DZone community and get the full member experience.Join For Free
In This Series:
- Distributed Tracing With Jaeger
- Simplifying the Setup With Tye (this article)
Tye is an experimental dotnet tool from Microsoft that aims to make developing, testing, and deploying microservices easier. Tye's opinionated nature greatly simplifies the lifecycle of development and deployment of .NET Core microservices.
To understand the benefits of Tye, let's enumerate the steps involved in the development and deployment of the DCalculator application to Kubernetes:
- Create dockerfiles for the services.
- Configure the address of the Log service in the Calculator service and ensure that the setting is appropriately configured in the various environments.
- Build containers and upload them to a container registry.
- Attach debugger to container processes.
- Write YAML specifications for services and apply them on your Kubernetes cluster to deploy your services.
- Store connection strings in Kubernetes secrets.
- Use tools such as K9s to view your application logs.
Project Tye removes all these steps from the developer workflow. You only need to write a simple configuration file, know a few commands, and Tye will take care of the rest.
Tye vs. Docker Compose
Docker Compose is an excellent tool for orchestrating containers. However, a complex application comprises multiple other components such as containers, executables, and .NET projects in local and remote repositories. Unlike Docker Compose, Tye is built for .NET applications and uses a convention-based model for service discovery, resolving dependencies, and automatic containerization of .NET applications.
Tye has several utilities that assist developers in developing applications and deploying them to Kubernetes without requiring them to write complex manifests and dockerfiles.
You can download the source code of the demo application from my GitHub repository.
Installation and Dashboard
Since Tye is still in preview, you need to specify the version of Tye that you wish to install. To install the latest version of Tye, execute the command specified in the NuGet page for Tye, which at the time of writing is the following:
Navigate to the root directory of your solution, which contains your project folders, and execute the following command:
Tye will automatically discover the .NET Core projects and execute
dotnet run for each of them. It will also host a dashboard at http://127.0.0.1:8000/ that lists the discovered services as follows:
The dashboard allows you to inspect the logs, metrics, bindings, and replicas. You can exit Tye by entering Ctrl + C in the console, and Tye will terminate all the services that it started.
Tye Configuration File
In addition to the services, the DCalculator application also consists of the Jaeger all-in-one container. To specify application dependencies and customize any other aspect of your solution, Tye relies on a YAML file called
tye.yaml. If Tye detects this file in the solution root folder, it stops the project discovery process and relies on the information in the file to discover the services.
To create the
tye.yaml file, execute the following command:
The configuration file generated by the
init command will already contain the details of the services discovered by Tye. Let's add the Jaeger service to the configuration as follows:
In addition to .NET Core projects, one of the service types supported by Tye is a Docker container. You can specify either the name of the container's image or the location of the Dockerfile, and Tye will configure and start the container appropriately.
Remember that Jaeger requires ports 14268 and 16686 for exposing the HTTP collector and the user interface. The Jaeger UDP collector can receive traces and spans on ports 5775, 6831, and 6832. However, due to an open issue with the container to host port mapping in Tye, we can't use the UDP collector with Tye currently. You can read more about the purpose of the various Jaeger ports in its deployment guide.
Tye bindings support the connection string property, which communicates the connection information to the other services. The Jaeger HTTP collector requires an instance of
HttpSender that takes the collector endpoint address as an argument. Rather than hardcoding the endpoint's address in code, we will surface the address as a connection string. You must have noticed that we can compose the connection string using binding properties such as
port. Apart from properties, you can interpolate environment variables in the connection string as well.
You must specify a name for the binding to uniquely identify it if there are more than one bindings of the same service. In addition to bindings, there are several options that you can configure to customize services in Tye. I recommend that you explore the YAML schema specification to understand the supported configuration settings and their expected values.
Start Docker Desktop and relaunch the Tye dashboard. You will find Jaeger service in the list of services managed by Tye.
Note that Tye used the binding information to expose the container ports that we configured to the host. You can navigate to the Jaeger UI at http://localhost:16686/ to verify whether the Jaeger instance is healthy.
Tye'ing the Services: Service Discovery With Tye
On every execution, Tye dynamically assigns ports to the Calculator and Log services. To help a service discover other services, Tye supplies the binding information of all the services to every service through environment variables. You can read more about how the process works in practice in the Service Discovery reference document.
You can install the Microsoft.Tye.Extensions.Configuration NuGet package that contains the logic to read the environment variables and find the address of the target service. The library adds a few extension methods to
IConfiguration to retrieve service addresses and connection strings from bindings.
Install the Microsoft.Tye.Extensions.Configuration NuGet package to the Calculator service and Log service projects. Let's first make modifications to the Calculator service to enable it to communicate with the Log service. Navigate to the
ConfigureServices method of the
Startup class and modify the base address used by the
HttpClient as follows:
Easy, isn't it? Let's also configure our Jaeger reporter to send traces to the HTTP collector endpoint that we configured in Tye. Update the method to resolve an instance of the
ITracer interface as follows:
GetConnectionString method takes the names of the service and the binding as input to resolve the value of the connection string. Since our Log service also depends on Jaeger, make the same change to the
ITracer resolver in the Log service.
Execute a few runs of the Calculator service using the Swagger UI, thereby generating a few traces. Visit the Jaeger dashboard at http://localhost:16686/ to view the traces generated by the services.
tye run command has several useful flags that you can use. For example, the
--watch flag configures Tye to watch the file system for any changes to the source code of services and restart the relevant service if a change is detected. The argument
--debug * will attach a debugger to all the services. You can replace the argument value
* with the name of a service to attach the debugger to the process running that service.
Running Services as Containers
Tye can package our services and execute them in containers without any additional effort. Execute the
tye run command with the
--docker flag as follows:
Upon execution, Tye will pull the base image for the projects, build the projects and images, create a network, and finally run containers from those images.
You can see that all the applications are now running as Linux-based containers. We did not have to write dockerfiles or establish networking between containers with docker-compose. Tye used the project structure and the dependencies specified in the configuration file to launch our application in containers.
As we discussed earlier, publishing an application to Kubernetes is a non-trivial activity. However, with Tye, you can deploy your application to Kubernetes by simply using the
tye deploy command. To deploy your application to a Kubernetes cluster, use the following command to launch the application deployment process in the interactive mode:
In interactive mode, you will receive prompts to enter details such as container registry and connection strings. You can read about deployment to Kubernetes using Tye in detail in the deployment reference document on GitHub. For now, let's inspect the Kubernetes manifest that Tye generates for our application using the following command:
generate command will create a file named
dCalculator-generate-production.yaml with the following content:
You can see that Tye created specifications of a deployment and a service object for each of our Calculator and Log services in the manifest. The secrets specified in the specifications are generated and applied when you execute the
In this article, we simplified our application development and deployment processes using Project Tye. Tye is currently an experimental tool but fast moving towards becoming a mature product.
Since Tye overlays existing tools such as Docker and Kubernetes, you can safely use it in your development workflow without affecting the production environment. If you liked this series or have any suggestions, please comment below or send me a tweet at @rahulrai_in.
Published at DZone with permission of Rahul Rai, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.