Where I kind of wrote out my current thoughts at the time about how it should work. And early on we had this idea that resource representation in the API would be the serialization format for everything. Like you would just be able to literally just serialize the API resources and use that for declarative configuration, use it for disaster recovery, use it for storage and etcd, use it everywhere. That was a brilliant design decision, I have to say. Like that worked awesome. That just worked fantastic. And I still think it's proven over ten years that it was a fantastic decision.
So we knew that had certain consequences, like we needed to have the resources be self describing. So this is why the API version in kind is in the body of every resource, even though it seems redundant with the rest path. It's like so what? It's redundant with the rest path. But that means if you have a representation of that on disk, the client tool can figure out what API to call from that representation without any external information. You don't need a client side provider layer of the kind that's in Terraform. You can actually just have a very simple client, a script even, that just extracts that information and cURLs the API and you're off to the races. So that was very empowering, because you could do things like run sed or some simpler unix tool over your config and then pipe it to cURL or whatever.
Our initial command line tool was called Cloud Config, which was then renamed to Kubeconfig, which was then replaced entirely by Kubectl. And with Kubectl we had a bunch of goals of making the foundation more solid and whatnot. But one of the things I really wanted to set up is support for declarative configuration in the future. A key aspect of that was a model for bulk operations. So instead of the G cloud model of putting the service name or the resource name first and then the verb after, and then the argument specific to that imperative operation, the way Kubectl works is the verb is first and after that come the nouns. And in some cases it could be a specific noun like Kubectl create config map blah blah blah. If you need to do something kind of imperative and very specific. But you can also just pass files, and those files can contain resource types that are heterogeneous. And any number of files and any number of resources. So that pattern reinforced the consistency across different resource types in the API and also paved the way for these bulk operations being able to manage multiple resources all at the same time. Because every use case in Kubernetes, every use case in cloud pretty much involves several resources. Like in kubernetes, a service and a deployment, or ingress service and deployment, or ingress service, deployment, config map, horizontal pod, autoscaler, etcetera.
So Apply we started working on and realized, well, it had some tricky aspects. Sam Ghods from Box wrote the initial Kubectl proposal and worked on that with us and wrote the initial Kubectl code and started figuring out okay, what is it going to take to be able to do Apply? And with Apply I really wanted to solve this problem of special case diff code. We didn't really entirely solve it until server side Apply, but this idea that fields in resources might get populated automatically, either because they're defaults or they're set by a mission control (which came later), or they're set by an asynchronous controller, like autoscaler is the canonical example. We wanted to be able to be tolerant of that. So you could specify a subset of the desired state and have that enforced declaratively, but you didn't necessarily have to control the full desired state. You could interoperate with other automation. So that was a key part of the design because I just saw so many special case hacks in Borg where that was not considered. Whether it's horizontal auto scaling or vertical auto scaling, or setting security settings, or automatically plugging in some application config values or whatever it is. I felt strongly that there was no hard line where you could say, oh, these things are going to be set by automation, and these things clearly will never be set by automation. I just did not believe that anybody would be able to draw that line in an accurate fashion. So I wanted a more general mechanism that could, what Daniel Smith called it is merging intent from both humans and robots, basically.
So I created SIG architecture to hold that power. We had kind of an explicit delegation of that responsibility to SIG architecture. To decide those high level project principles, things like API conventions. We created this production readiness review effort to ensure that new features would be sufficiently observable and reliable and tested and things like that.
The conformance program was put under SIG Architecture's purview as well, to kind of define what is the expected behavior of Kubernetes and maintain that over time. We also developed this KEP process, the Kubernetes enhancement proposals. We had an informal design documentation process since the very early days of the project. As we brought in more and more people that was formalized into this KEP process. So the people who would review those KEPs would be the technical deciders for those areas. So that would give the opportunity for broader review within the project, since there was a process for publishing the KEPs and a period for reviewing them. But, you know, also ensure that things got reviewed before they got added to the codebase.
As it so happens, we also started pushing code into extensions with CRDs and other repos. So we let the SIGs kind of create their own repos in the Kubernetes SIGs organization on GitHub and experiment with things because we didn't want to actually block progress. But if they're going to be in Kubernetes by default, then we wanted to have a higher bar. So I felt like that part of the process worked pretty well. Kustomize started in one of these SIG Cli repo as a totally separate tool before it was brought into Kubectl.
But yeah, I mean, over time the project has matured, has slowed down, has a huge ecosystem around it. So you don't necessarily need to be in the Kubernetes project to create functionality related to Kubernetes in your own project, in your own tool. And sometimes that's even better because as a standalone project, to some degree, you can have your own brand, make your own decisions, have your own community around it. Under the Kubernetes umbrella, the project's so huge, things can get lost or drowned out. Kubernetes releases have always been pretty big, things can definitely get lost in the noise there.
I don't know how many all time contributors there were now, but as of like two thousand eighteen or two thousand nineteen, I think there were around 50,000 all time contributors. Which just seems nuts!