Skip to content

Commit 54636b9

Browse files
authored
guide documenting techniques for variant constructor (#3083)
1 parent aa115d3 commit 54636b9

File tree

4 files changed

+183
-0
lines changed

4 files changed

+183
-0
lines changed

scripts/generate_site_sidebar/sidebar_template.md.tmpl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,5 +60,6 @@
6060
- [Namespace provisioning UI](guides/namespace-provisioning-ui.md)
6161
- [Porch Installation Guide](guides/porch-installation.md)
6262
- [Porch User Guide](guides/porch-user-guide.md)
63+
- [Variant Constructor Pattern](guides/variant-constructor-pattern.md)
6364
- [FAQ](faq/)
6465
- [Contact](contact/)
Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
# Variant construction pattern
2+
3+
If you look at the config workflows, you will notice that creating a variant
4+
of a package is a very frequent operation, so reducing the steps
5+
required to create a variant can have significant benefits for the
6+
package consumers. In this guide, we will look at some techniques
7+
that a package author can use to enable automatic variant construction of a package.
8+
9+
## Types of packages
10+
11+
kpt packages comes in two flavors: `abstract package` and
12+
`deployable instance`. An `abstract` package is a reususable package that
13+
is used to create deployable instances that can be deployed to a
14+
kubernetes cluster. In programming language terms, you can think of an `abstract`
15+
packages as the class and `deployable instance` as the instances of the class.
16+
`deployable` instances of package are also referred to as `variant` of the package.
17+
18+
Figure below shows a `package catalog` on the left that has `abstract` packages
19+
and `deployable instances` on the right. A good pattern is to keep the abstract
20+
packages and instance packages in separate repos and typically
21+
`deployable instances` repo will be setup to auto deploy to a kubernetes cluster
22+
using gitops tools such as `config-sync`, `fluxcd`, `argocd`.
23+
24+
![variant constructor pkg repo diagram](/static/images/variant-constructor-pkg-repo-diagram.png)
25+
26+
Resources in an `abstract` package have placeholder values that need to be
27+
substituted with actual values to make them ready for deployment.
28+
For example, the name of the namespace resource below has `example` as a placeholder
29+
value. This is a part of the `abstract package`.
30+
31+
```yaml
32+
apiVersion:v1
33+
kind: Namespace
34+
metadata:
35+
name: example # <-- this is a placeholder value
36+
```
37+
38+
## Customizing identity of resources
39+
40+
A kpt package contains kubernetes resources. Whenever you are creating a
41+
variant of the package, first step is to ensure unique identity of the
42+
resources in that variant. For example, if the abstract package contains a
43+
`namespace` resource, then the variant package should contain a `namespace` resource
44+
corresponding to that variant.
45+
46+
In a kubernetes cluster, resources are identified by their group, version, kind,
47+
namespace and name (also referred to as GVKNN). If resource is cluster scoped,
48+
then the `metadata.name` uniquely identifies the resource in a cluster. If the resource
49+
is namespace scoped, then (`metadata.namespace`, `name`) together identifies the
50+
resource uniquely.
51+
52+
[kpt-function-catalog](https://catalog.kpt.dev) provides two function that helps
53+
with customizing the identify of the resources:
54+
55+
1. [set-namespace](https://catalog.kpt.dev/set-namespace/v0.3/): sets the
56+
namespace for all resources in the package.
57+
2. [ensure-name-substring](https://catalog.kpt.dev/ensure-name-substring/v0.2/):
58+
sets the name of the resources in the package.
59+
60+
You can use the appropriate functions from the catalog or implement a custom
61+
function to ensure unique identity of the resources.
62+
63+
## Customizing non-identifier fields of resources
64+
65+
Packages can use other functions such as `set-labels`, `set-annotations`, `apply-replacements`
66+
or custom functions to transform other fields of resources.
67+
68+
## Core mechanism
69+
70+
Enabling automatic variant construction involves two steps:
71+
72+
1. Use functions to customize identity or other fields of the resources
73+
2. Generating inputs for the functions declarared in the package
74+
75+
Here is an example of `Kptfile` of a package that uses `set-namespace` and `apply-transform`
76+
to enable customization.
77+
78+
```Kptfile
79+
# Kptfile
80+
...
81+
pipeline:
82+
mutators:
83+
- image: set-namespace:v0.3.4
84+
configPath: ...
85+
- image: apply-transform:v0.1.0
86+
configPath: ...
87+
...
88+
```
89+
90+
Now let's talk about the input to the functions. In most cases, variant's name
91+
(deployable instance name) itself can be used to derive unique identity
92+
of the resources in the variant. For example, if I create a variant of
93+
`microservice` package, I will name the deployable instance to
94+
`user-service` or `order-service`. So if the package's name is available to the
95+
functions, then they can use it to customize the name/namespace of the resources.
96+
So, starting with `kpt v1.0.0-beta.15+`, kpt makes `package name` available
97+
in a `ConfigMap` at a well-known path `package-context.yaml` in `data.name` field.
98+
The `package-context.yaml` is available to functions during `kpt fn render|eval`.
99+
100+
Here are examples of `package-context.yaml` for abstract and deployable instance:
101+
102+
```yaml
103+
# package-context.yaml
104+
# package context for an abstract package.
105+
# This is automatically created on `kpt pkg init`.
106+
apiVersion: v1
107+
kind: ConfigMap
108+
data:
109+
name: example # <-- placeholder value
110+
```
111+
112+
```yaml
113+
# package-context.yaml
114+
# package context for a deployable instance of a package.
115+
# This is automatically populated during `kpt pkg get`.
116+
apiVersion: v1
117+
kind: ConfigMap
118+
data:
119+
name: my-pkg-instance # <- deployable instance name
120+
```
121+
122+
kpt supports a way to create `deployable instance` such that `package-context.yaml`
123+
is automatically populated with the `deployable instance`'s name.
124+
125+
```shell
126+
$kpt pkg get <pkg-location> my-pkg-instance --for-deployment
127+
```
128+
129+
Now, let's look at how to provide the input to the functions.
130+
131+
If you are using `set-namespace` function in your package, then
132+
`set-namespace` function supports reading input from `package-context.yaml`.
133+
Here is an example:
134+
135+
```Kptfile
136+
...
137+
pipeline:
138+
mutators:
139+
- image: set-namespace:v0.3.4
140+
configPath: package-context.yaml
141+
...
142+
```
143+
144+
By using `package-context.yaml` as input, `set-namespace` uses the value `example`
145+
for an `abstract` package and variant's name for a deployable instance. The
146+
same pattern can be applied to other functions also. For example, the
147+
[`namespace provisioning`](https://github.com/GoogleContainerTools/kpt-samples/tree/main/basens)
148+
package uses `apply-replacements` function to set the RoleBinding group
149+
using the name of the package.
150+
151+
In some cases, the inputs needed to generate the variant will come from
152+
some external system or environment. Those can be generated imperatively or
153+
manually edited after the package is forked using `kpt pkg get`. Additional
154+
customizations could also be made at that point.
155+
156+
So for a package consumer, creating a deployable instance involves the following:
157+
158+
```shell
159+
# pick name of the deployable instance say `my-pkg-instance`
160+
$ kpt pkg get <path-to-abstract-pkg> <my-pkg-instance> --for-deployement
161+
162+
$ kpt fn render <my-pkg-instance>
163+
164+
```
165+
166+
## See it in action
167+
168+
If you want to see `variant constructor pattern` in action for a real use-case,
169+
check out [`namespace provisioning using kpt CLI guide`](/guides/namespace-provisioning-cli.md).
170+
171+
## Summary
172+
173+
With the above pattern and workflow, you can see - how a package publisher can
174+
enable automatic customization of deployable instance of a package with minimal
175+
input i.e. package instance name.
176+
177+
## Future plans
178+
179+
Currently `--for-deployment` steps invokes built-in function to generate
180+
`package-context.yaml`. We would like to make it extensible for users to invoke their
181+
custom function for deploy workflow.

site/sidebar.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,5 +94,6 @@
9494
- [Namespace provisioning UI](guides/namespace-provisioning-ui.md)
9595
- [Porch Installation Guide](guides/porch-installation.md)
9696
- [Porch User Guide](guides/porch-user-guide.md)
97+
- [Variant Constructor Pattern](guides/variant-constructor-pattern.md)
9798
- [FAQ](faq/)
9899
- [Contact](contact/)
25.7 KB
Loading

0 commit comments

Comments
 (0)