Embed Manifests Inline: Streamlining Crossplane Docs
Hey guys! Let's talk about how we can make our Crossplane documentation even better, especially when it comes to showing off those crucial example manifests. We all know how vital these manifests are, particularly for folks just getting started. They’re the hands-on guide that helps users grasp the concepts and get things running smoothly. Over the years, we've tried a few different ways to present them, but honestly, we haven’t always been consistent. So, let’s dive into the current methods and why a change could really benefit our users.
Current Approaches and Their Downsides
Plain YAML with Save-and-Apply Instructions
One method we've used is presenting plain YAML code snippets. The idea is straightforward: we show the YAML, and then we instruct users to save this code into a file (like my-manifest.yaml
) and then apply it using kubectl apply -f my-manifest.yaml
. This approach is clean and simple at first glance. The YAML itself is uncluttered, making it easy to read and understand the manifest's structure. We are giving users the raw material, the core configuration, without any additional layers of complexity. It's like handing someone a recipe written in its purest form.
However, the convenience factor for the user isn't the best. Think about it from their perspective. They have to copy the YAML, open a text editor, paste the code, save the file, and then finally run the kubectl apply
command. That's a fair few steps, especially if they're trying out multiple examples or iterating on configurations. Each of these steps introduces a small hurdle, and these hurdles can add up, especially for newcomers who are already navigating a new system. We want to make the initial experience as smooth as possible, and this method, while straightforward, might not be the most user-friendly in terms of immediate action.
Also, consider the context-switching involved. Users are moving between the documentation, their text editor, and the command line. Each switch breaks their flow and requires mental re-engagement. It's not a huge deal, but it's a subtle friction point that we can address. We're aiming for a learning experience that minimizes friction, allowing users to focus on understanding and experimenting with Crossplane, rather than wrestling with file management.
YAML Wrapped in kubectl apply
Commands
Another tactic we've employed is wrapping the YAML manifest inside a kubectl apply
command, often using a bash HERE/EOF document. This looks something like this:
kubectl apply <<EOF
apiVersion: ...
kind: ...
metadata:
...
spec:
...
EOF
This method has the advantage of being copy-and-paste friendly directly into the terminal. Users can grab the entire block and execute it, which seems like a step up in convenience compared to the save-to-file approach. By including the kubectl apply
command directly, we're theoretically reducing the number of steps a user needs to take. We're packaging the action with the manifest, aiming to provide a more immediate and seamless experience.
However, the readability of the YAML manifest itself suffers. The shell syntax (<<EOF
and EOF
) adds visual clutter, making the actual YAML harder to parse at a glance. The core configuration gets masked by the surrounding shell commands, which can be a significant drawback. When users are trying to learn, clarity is paramount. They need to be able to quickly grasp the structure and content of the manifest, and extra visual noise works against this goal. It's like trying to read a recipe where the ingredients and instructions are interspersed with extra symbols and formatting—it slows you down and makes it harder to focus on what matters.
Furthermore, this approach introduces a layer of shell scripting that might be unfamiliar to some users. While kubectl apply
is a common command, the HERE/EOF syntax might be new territory, especially for those who are not deeply familiar with bash or other shell environments. This added complexity can be a barrier to entry, making the documentation feel more intimidating. Our goal is to make Crossplane accessible to everyone, regardless of their background, and we want to avoid introducing unnecessary hurdles.
Plain YAML with Duplicated Manifests in a Directory
Then, there’s the approach where we present plain YAML in the documentation, but also maintain duplicate copies of these manifests in a dedicated directory within the repository. This allows users to apply the manifests directly from the web using a command like kubectl apply -f https://docs.crossplane.io/v2.0/manifests/...
. This method seems quite appealing because it combines the clarity of plain YAML with the convenience of direct application.
The big problem here is maintenance. Keeping those manifests in sync is a chore, guys. It's so easy for them to drift apart, and then our examples are wrong. Wrong examples are worse than no examples. It leads to user frustration, confusion, and ultimately undermines the credibility of our documentation. Imagine a user meticulously following our guide, only to encounter errors because the manifest they're using doesn't match what's described in the text. That's a terrible experience, and it's something we want to avoid at all costs.
The Suggested Solution: Inline Embedding with Hugo
So, after a bit of brainstorming, especially with the brilliant @tr0njavolta, we've landed on a solution that seems to hit the sweet spot. It's a variant of the third approach, but with a crucial twist that addresses the maintenance issue. The core idea is this:
- We define our manifests only in files within a dedicated directory in our documentation repository. Think something like
content/manifests/
. This becomes our single source of truth for all example manifests. - We leverage Hugo, our static site generator, to embed these manifests inline within the documentation pages. This means that the YAML code you see in the documentation is pulled directly from these files. It's not a copy; it's the real deal.
- We then show users how to apply these manifests using the
kubectl apply -f https://docs.crossplane.io/v2.0/manifests/...
style command. This provides a clear and direct way for them to use the examples.
This approach is a winner for several reasons. First, it keeps our manifests clean and readable. We're presenting plain YAML, which is the most straightforward way to convey the configuration. There's no shell syntax or other distractions to get in the way. Second, it ensures consistency. Because the manifests are embedded directly from the files, we eliminate the risk of discrepancies between the documentation and the actual examples. What you see is what you get, and that's a huge win for user trust and confidence. Third, it streamlines maintenance. We only need to update the manifest in one place, and the changes automatically propagate to the documentation. This saves us time, reduces the chance of errors, and keeps our examples fresh and accurate.
Why This Mirrors the Kubernetes Docs Approach
Interestingly, this approach aligns closely with what the Kubernetes documentation does, and that's not by accident. The Kubernetes docs are widely regarded as a gold standard in the industry, and for good reason. They've put a lot of thought and effort into creating a user-friendly and effective learning experience. By adopting a similar strategy, we're not just borrowing a technical solution; we're also aligning ourselves with a proven philosophy of documentation excellence. We're saying,