Experimental Kubernetes Operator kit written in Rust
Documentation:
This project is maintained by psFried
We’re finally ready to put all the pieces together and get this operator running!
All the functions we need are defined in the roperator::runner module and re-exported in the roperator::prelude module. The functions there all accept both an OperatorConfig and an impl Handler. The run_operator function accepts only those two arguments, while run_operator_with_client_config allows you to specify the ClientConfig for cases where you need to customize how roperator connects to the Kubernetes API server. The body of a typical main function might look something like the following:
env_logger::init();
let config = create_operator_config();
let handler = MyHandler::new();
let error = roperator::runner::run_operator(config, handler);
log::error!("operator exited with error: {:?}", error);
std::process::exit(1);
The run_operator and run_operator_with_client_config functions are both meant to run the operator indefinitely, as you would in a production container. They do not ever return under normal circumstances, and thus they do not return a Result, since it would never return the Ok variant.
If you want to run locally against a GKE cluster, then you’ll need to use run_operator_with_client_config, since Roperator doesn’t support oauth. Check out the instructions for authenticating with GKE for information on how to authenticate using a service account for testing locally.
To run your operator, you’ll need both an OperatorConfig and a ClientConfig. The OperatorConfig contains information about what your operator will do, the types of resources that it will manage, etc. The ClientConfig contains information about how to connect to the Kubernetes Cluster and interact with it. In most cases, the ClientConfig can be determined automatically, which is what happens in the run_operator function. But in some scenarios (notably, local development environments connecting to GKE) you’ll need control over the ClientConfig. The run_operator_with_client_config function allows you to pass a custom ClientConfig. See the advanced client configuration section if you need to use that.
Roperator is just a library, so you’re responsible for building an image and deploying a container on your own. We do have a bit of useful advice, though.
StatefulSet with only a single replica. While Deployments are great for a lot of things, they’re not ideal for operators due to their behavior when you make changes to the deployment spec. Deployments will typically start the new version before they shutdown the old one, which can result in multiple instance of your operator running at the same time and trying to update the same resources. It’s safest to use a StatefulSet instead, which ensures that at most a single instance is running as long as you set the replicas to 1.run_operator returns an error, just exit with a non-zero status. Critical errors in your operator shoud be extremely rare, since most error conditions are handled internally. If run_operator returns an error, then it’s probably something pretty serious and not recoverable. Let the container die and get re-created by the controller.OperatorConfig, you can check your program arguments or an env variable and set a namespace on it if desired. This allows you the flexibility to deploy either cluster-wide or for only a specific namespace.Roperator of course needs authorization to update any of the resources it manages. In most production clusters, this means using RBAC. For operators that will run within a single namespace, a regular Role and RoleBinding can be used. For cluster-scoped operators, you’ll need a ClusterRole and ClusterRoleBinding.
For your parent resource (usually a CRD you’ve defined), you’ll need to ensure that your rules include access to update the status subresource. Such a rule might look like the following:
rules:
- apiGroups: ["mygroup"]
resources: ["mycsutomresources", "mycsutomresources/status"]
verbs: ["get", "list", "watch", "update", "patch"]
For each type of child resource that’s included in your OperatorConfig, you’ll also need to allow all of the verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]