Cloud Native Blog - Container Solutions

We Built a .NET Operator SDK (So You Don’t Have To)

Written by Sebastián Gómez | Mar 16, 2021 3:16:12 PM

We built a .NET Operator SDK, in C#, so you can build your own Kubernetes Operators in C# or any .NET language. There's of course the Go Operator SDK, and there's our Java Operator SDK, so why not having something for the .NET community?

This post assumes you are familiar with Kubernetes and the Operator pattern. If it's not your case, you might want to head over to the "Kubernetes Operators Explained" post. 

Why do you need this?

Say you have been developing on the Microsoft stack for ages. You jumped right into the first version of the .NET Framework and loved the idea of the “new” ASP.NET. You built your first site using WebForms. From that moment forward you have evolved your application along with the versions of the framework. A few years ago you heard about .NET Core and thought, “Oh cool! Now I’ll be able to run my application in a Linux box.”

Then Docker showed up in your life, and of course, after containerising your application you found yourself in the need for an orchestrator. Luckily for you, Kubernetes was also around.

Once you get to know Kubernetes and implement GitOps around it, it becomes critical that every piece of your application becomes a Kubernetes object. So you’ll basically start to have YAML files for everything. You have your deployments, services, ingress, probably some network policies, and everything around your application starts to get simpler, you can start to worry about the “other stuff”. By “other stuff” I mean things that are not Kubernetes native objects, like your database, creating database tables, maybe scheduling a backup, or even something specific for your application.

That’s when you learnt about controllers or operators, but… do you have to learn Go?

No! You don't have to learn Go in order to work with Kubernetes!

Introducing .NET Operator SDK

You have a team of rock star developers in C#. Do you hire some Go developers, do you make your team learn Go?

Luckily for you, you can now write your own controllers/operators with the language and framework you know and love.

The .NET Operator SDK is a thin wrapper around the official Kubernetes C# client that allows you to easily create your own operator. It actually provides you with the right interfaces to implement and a controller engine that does all the heavy lifting of calling the Kubernetes API and iterating the reconciliation loop. 

It takes care of calling the right APIs, it manages your current state, and it will call all your functions in case one of your objects was either added, deleted, or updated. It's also self-healing, meaning that if you mess up something while updating your resources, the controller itself will keep running and you can try to fix whatever is broken.

Here's how it works.

SDK internals

The .NET Operator SDK provides a class from which the operator class must inherit, an interface where you will write your functions (add, delete, update) and the controller class, which you need to initialize with your class and call the StartAsync method.

Going deeper

This function will call the Kubernetes API and request for the objects your operator observes. Every time there’s an event (an add, update or delete) it will call the functions you implemented on your operator.

But it will also call your ReconciliationLoop. One of the functions you must implement in your operator deals with the fact that maybe your resource is down—and, in that case, you need to figure out what to do. Think of it like the deployment’s controller. This controller not only spins up new pods when you create a deployment, but it also recreates pods if they fail and are terminated. In other words, the controllers make sure that the actual state is the same as the desired state.

Here's a small example from the MSSQL Database Operator, which is a sample operator built with the .NET Operator SDK.


foreach (string key in m_currentState Keys.ToList()) 
{ 
	MSSQLDB db = m_currentState[key];
	using (SqlConnection connection = GetDBConnection(k8s, db))
	{ 
		connection Open();
		SqlCommand queryCommand = new SqlCommand($"SELECT COUNT(*) 
FROM SYS.DATABASES WHERE NAME = '{db.Spec.DBName}';", connection);

		try 
    	{ 
    		int i = (int)queryCommand.ExecuteScalar();

			if(i == 0)
			{
				Log.Warn($"Database {db.Spec.DBName} ({db.Name()}) 
was not found!");
      	      	CreateDB(k8s, db);
			}
		}
   	 	catch (Exception ex)
		{
			Log.Error(ex.Message);
		}
	}
}

Here you see that we basically iterate through a cache of the created databases, and query the Sql Server instance to check if the databases are in fact there (registered under the sys.database system table). Then, if no records are found (for each database) it will try to create it (again). 

Conclusion

I hope I made the point, but in case you missed it: No, you don't have to learn Go in order to work with Kubernetes! You can now use the framework you know and love to build your own Kubernetes Operators, and have them running in your cluster in no time.

So, is it something you think you might need? Maybe you never thought about until now that you can use C#. CustomResourceDefinitions are the Kubernetes native way of having everything into the same way of working. Configuring secrets, deploying a new database, (or maybe just a table), spin up a new logging solution, or maybe an observability cluster: everything should be handled natively by Kubernetes, and so do your own custom resources.  

Interested in what we're doing? Go over to the repo and take a look, maybe you can help us improve it.

Photo by Eduardo Sánchez on Unsplash