 Hello and welcome to my presentation. Own your YAML, Extending Customize Via Plugins. My name is Matt McEwen. I'm a member of the Airship Working Committee and a lead member of technical staff at AT&T. First, I'll give a bit of an overview of customize itself, what it is and why you'd use it and how its functionality can be extended via plugins. I'll then give some examples of what customize plugins can do by looking at plugins hosted by the Airship project. I'll touch on how customize can be used for declarative intent at scale and then I'll give a short demo using one of the Airship plugins. So what is customize and why would you want to use it? Customize is a tool and a go library in the Kubernetes community, which focuses on the ability to take base generic Kubernetes deployment configuration and to easily apply site specific, operator specific or use case specific changes on top of that base. You should be able to consume and customize upstream Kubernetes deployment definitions without having to fork them. Customize helps you adhere to the don't repeat yourself principle in the Kubernetes world. So for example, let's say we want to deploy an upstream open source game on our own Kubernetes cluster. And let's say that its configuration is represented by a Kubernetes config map. If this example looks familiar, it's because it's from the Kubernetes documentation for a config map. And let's say that the default configuration from the upstream source is perfect for us, except that for our deployment, we want to change the number of lives that a player starts with. In production, we think five lives is a good number for us because we want to be a little bit easier in our implementation. And in our development environment, we want to start the user with a hundred lives to make testing easy. The straightforward approach would be to take the upstream config map and make one copy for dev and one for production. But now of course, any changes that are made upstream are missed downstream and any changes you make to dev or missed in prod unless you copy configuration in an ongoing basis which can be considerably time consuming and error prone. Customize approaches this problem with the concept of a set of base resources which contain good general purpose defaults and which you might get from an upstream third party like our config map example. And then it uses the concept of customizing those resources, hence the name with use case specific targeted overrides which keep site specific configuration lean and focused. In this example, the green box represents the upstream base for our config map and the blue and tan boxes are patches that get applied for dev and for prod, respectively. The only thing in these patch boxes are the identifying information for the resource you want to patch, the name, the kind and the API version as well as the specific data that you want to override, data.player initial lives to 100 or to five. Everything else is inherited as is from the base resource. The gray box then is the customization YAML that glues it all together by specifying a base resource upstream game as well as the patch to apply which will be different in dev versus prod. Customize executes plugins when it finds a plugin configuration file referenced in customization.yaml. Here on the left, you see a transformers stanza that specifies a plugin configuration file. There are two main types of plugins, generator plugins can create new resources based on the generator configuration and transformer plugins can modify a set of inherited base resources. Customize has a current state mechanism to invoke plugins from the local file system but it's moving to a new target state mechanism that uses what are known as KRM or kept functions for plugins which allows plugins to be executed via container image, name, and tag which is a lot more modular and straightforward. And now for the sake of example we're going to look at three plugins hosted by the airship project, the replacement transformer, the templator, and the SOPS plugin. The replacement transformer is as you probably guessed a transformer type plugin. Its purpose is to deduplicate and centralize information that should be shared across multiple resources by copying data from source resources into target resources. It supports replacement of YAML trees, regular expression-based replacement of substrings and replacement of list items. In this example, you can see a plugin configuration of type replacement transformer which gets the player initial lives out of the source document and then copies it into the target document which in this case is our config map. So you see the mapping rules from a source to a target in the plugin configuration and then the player initial lives of 100 is copied into the target according to those rules in the output. This becomes very helpful when you have many resources that need to know the same information because it lets you define and change those configurations in one place and then copy that shared value to everything that needs to know about it. The next example is the templator, a generator plugin whose purpose is to deduplicate resources that are nearly identical to one another by creating them from a parameterized Go template. It should feel very familiar to Helm chart developers since it provides the sprig Go TPL library as well as the two YAML function from the Helm project itself. You can also pair the templator plugin up with the replacement transformer to inject site-specific variables into your template values. In this example, we have a plugin configuration of type templator which contains a template for a config map as well as some template inputs in the form of config map names. And since we provided three different config map names to our plugin configuration, three different config maps are generated that only differ by the templated in name. One good example of how Airship uses this plugin is to create bare-metal host resources for use with the metal-cubed bare-metal provisioning project. These are large Kubernetes resources that are mostly the same, but differ on a few key points like IP addresses and host names. Finally, Airship's SOPS plugin supports the encryption of sensitive pieces of YAML at rest. For example, passwords and keys that need to be provided to Kubernetes-based applications. This transformer plugin uses the open-source SOPS project for YAML encryption to decrypt sensitive data just in time from an encrypted version that you typically commit to your Git repo. You see in this example, the input YAML contains an encrypted version of player initial lives. Along with an annotation that the SOPS plugin watches for and some metadata to SOPS itself about the encrypted payload. The SOPS plugin has access to a decryption key and it applies it to all the annotated encrypted fields that it finds in its input YAMLs. In an Airship context, the clear text payload is then delivered directly to the Kubernetes API server without touching the local disk. There are actually three different SOPS-related customized plugins that I've seen to an addition to the Airship one. So if this is interesting to you, you have some options. So how can Customize help you configure software at scale across many different use cases and sites? It's important to understand that Customize supports layering multiple customizations on top of each other. This is a simplified view of how the Airship Treasure Map project uses this concept. Fine grained declarative intent such as the OpenStack Helm charts or Kubernetes operators are captured in their own base configurations which are composed together into any number of use cases that we call deployment types. In this example, the network cloud type pulls in an infrastructure base and an OpenStack base using Customize. Then any number of site definitions can be customized on top of the network cloud type. This results in very little duplication of declarative intent, especially when plugins such as the replacement transformer and templator are used. The key here is that the configuration is defined as far upward in this scheme as possible. And briefly, a few other places that Airship wraps around Customize for enhanced usability include the ability to deploy curated and integrated bases of infrastructure across bare metal Kubernetes, public cloud and OpenStack Kubernetes clusters in addition to workload management on top of the clusters, cross repository dependency management. For example, you can make your own network cloud site using the TreasureMap project base definition of a network cloud. Airship can sequence deployments into phases, can visualize nested customizations in a tree view and provides plugins that we looked at today. And now for a brief live demo. Since this is a prerecorded talk, you'll just have to trust me that the demo was live when I recorded this. All right. So for our example, you'll see that we've defined a base, Customize base called Kubernetes control. The contents of this base are the control plane for a Kubernetes cluster as defined by the Kubernetes cluster API. It also includes a metal cubed specific additions to that definition so that it can be deployed in a metal cubed bare metal Kubernetes context. And then we have a inheriting customization on top of that that we'll look at in a second. But first, let's take a quick look at the base. Here you see a couple of different Kubernetes resources, a CAPI cluster and a metal three cluster. The metal three cluster includes, you'll notice a control plane endpoint host IP. That's what we want to concentrate on for this example because although the majority of the contents of the Kubernetes control plane base definition are generic, this control plane endpoint IP address is going to vary for every site that we need to deploy to. So now let's look at how we can override that value via the customization. Here is the customization.yaml. And we're going to use the replacement transformer plugin that we looked at before, which as you recall, uses a source document, which in our case, contains a bunch of networking information for the site, as well as a target resource, which in our case comes from the Kubernetes control base, as well as mapping rules that shuffle data from the source to the target. Those are part of this plugin config. This is the plugin config. You'll see three different sets of sources and targets, but let's take a look at this third one where we take the Kubernetes control plane endpoint out of a resource named networking catalog and put it into the spec.controlplane endpoint of a Metal 3 cluster resource. And that's the one that we were just looking at from the base. Here is the source document, and you'll notice a number of different fields in here that are consumed in an actual airship context by a number of different bases. The one we care about is the kubernetes.controlplaneendpoint.host. And here you see the same default that we were looking at, so it doesn't really override anything yet. And then if we render, if we use customize to render these resources, and I have a alias here that wraps up a few different command line parameters that you have to pass to customize to be able to use plugins, you'll see it renders the entirety of the input and the customization and spits out a bunch of YAML. But I'll call your attention to at the bottom here, it spits out the Metal 3 cluster object that we looked at with the default IP address. So let's say that we want to customize this for a particular site, then that site would get its own copy of this networking catalog. Let's say that it would have an 11.23 IP address for its control plane. And if we render it again, you'll see that the host IP address in the Metal 3 cluster is updated to reflect the contents of this consolidated network catalog document. All right, thank you all very much for participating in my talk today. I hope you find some interesting ways to use customize in your own Kubernetes experience. And if you're interested in learning more about airship, we have a few resources on this slide as well as several other talks at the summit. And you're most welcome to come to our new developer onboarding session at the PTG next week. Thank you very much.