How to utilize kustomize processing directives to minimize yaml errors and simplify yaml resources.
In many cases there are resources along what is below:
- CustomResourceDefinition
- ClusterRole, ClusterRoleBinding or Role, RoleBinding
- ConfigMap
- Deployment
- Service
- ServiceAccount
- VirtualService
This collection of resources should by grouped under a particular parent folder (eg tf-job-operator, etc), within a subfolder 'base'.
Resources should be organized by kind, where the resource is in a file that is the lower-case hyphenized form of the Resource kind. For example: a Deployment would go in a file named deployment.yaml. A ClusterRoleBinding would go in a file called cluster-role-binding.yaml. If there are multiple resources within a kustomize target (eg more than one deployment), you may want to maintain a single resource per file and add a prefix|suffix of the resource name to the filename. For example the file name would be <kind>-<name>.yaml
. See below for an example.
example: /manifests/profiles
profiles
└── base
├── README.md
├── cluster-role-binding.yaml
├── crd.yaml
├── deployment.yaml
├── kustomization.yaml
├── role-binding.yaml
├── role.yaml
├── service-account.yaml
└── service.yaml
There are often repeated attributes across resources: labels, namespace, or perhaps a common prefix used for each resource. You can move name prefixes into the kustomization.yaml file and then make adjustments within each resource; removing the prefix from its name. Additionaly you can move labels and their selectors into the kustomization.yaml. Yo can move the namespace into the kustomization.yaml. All of these will be added back into the resource by running kustomize build
.
example: /manifests/profiles/base/kustomization.yaml. Contains namespace, nameprefix, commonLabels.
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- crd.yaml
- service-account.yaml
- cluster-role-binding.yaml
- role.yaml
- role-binding.yaml
- service.yaml
- deployment.yaml
namespace: kubeflow
namePrefix: profiles-
commonLabels:
kustomize.component: profiles
images:
- name: gcr.io/kubeflow-images-public/profile-controller
newName: gcr.io/kubeflow-images-public/profile-controller
newTag: v20190228-v0.4.0-rc.1-192-g1a802656-dirty-f95773
The original deployment in profiles looked like:
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
kustomize.component: profiles
name: profiles-deployment
namespace: kubeflow
spec:
selector:
matchLabels:
kustomize.component: profiles
template:
metadata:
labels:
kustomize.component: profiles
spec:
containers:
- command:
- /manager
image: gcr.io/kubeflow-images-public/profile-controller:v20190228-v0.4.0-rc.1-192-g1a802656-dirty-f95773
imagePullPolicy: Always
name: manager
serviceAccountName: profiles-controller-service-account
Moving labels, namespace and the nameprefix 'profiles-' to kustomization.yaml reduces deployment.yaml to
apiVersion: apps/v1
kind: Deployment
metadata:
name: deployment
spec:
template:
spec:
containers:
- name: manager
command:
- /manager
image: gcr.io/kubeflow-images-public/profile-controller:v20190228-v0.4.0-rc.1-192-g1a802656-dirty-f95773
imagePullPolicy: Always
serviceAccountName: controller-service-account
Note: A kustomize target should always 'build', so you should add what's needed to allow a kustomize build
to succeed (and for unittests to work). Defining a namespace in kustomization.yaml is required to run kustomize build
, even though there is a namespace override in the parent kustomization.yaml generated by kfctl under /manifests/profiles. This generated kustomization.yaml provides overrides using values from app.yaml and will appear within the manifest cache after running kfctl generate...
.
There are 3 types of kustomize parameters that can be leveraged when building a kustomize target. The vars, patchesStrategicMerge and patchesJson6209 are described in detail in the kustomization.yaml file.
- vars
Kustomize vars should be used whenever a simple text replacement is needed. The text must be a string, for example you cannot use kustomize vars for deployment.spec.replicas which takes a int. You will need to use a Json Patch for this. Kustomize vars require a section within the kustomization.yaml undervars:
that identifies the variable name, its object reference and optionally its field reference in the object. This uniquely identifies the source of the variable. A configuration yaml may also be needed to identify those resources referencing the variable. In many cases the variable will reference a ConfigMap that is generated in the kustomization.yaml file using values contained in a params.env file. The configuration yaml will then list resources and their json paths where the variable is used eg $(varname). See ambassador for an example of using a var named ambassadorServiceType that is generated from a configMapGenerator which reads this value from params.env. In order to use ambassadorServiceType, you need to list which resource uses it in params.yaml and finally, actually use the variable. - patchesStrategicMerge
This contains a list of resources which have one or more changes from the base resource. Only the changes and enough information to uniquely describe the resource should be in this resource file. This should not be used if you're changing an array in the base resource. For this you should use a Json Patch. - patchesJson6902
Json Patches are the most versatile, having the ability to add, replace or remove array entries in resources (egdeployment/spec/template/spec/containers/env/[-+]
) as well as other sections that may be parts of the schema or integers. [Ambassador]'s kustomization.yaml also contains an example of a json patch that replaces an integer using the patch found in deployment-amabassador-patch.yaml in the ambassador base directory.
Certain resources or resource modifications can be further grouped by a particular concept that cuts across kustomize base targets such as platform type, an Istio service, basic-auth, etc. There are a number of examples where base targets are changed by specific overlays and can be used as a reference when adding a new target or overlay. One example of an overlay is under profiles debug overlay. In this case, there is a need to debug the profile-controller using dlv/GoLand. This requires replacing the deployment command with '/go/bin/dlv' and adding args required by dlv. It also requires replacing the image with one that has been modified and matches with the debugger source code.
Overlays can be used directly by running kustomize build
at the overlay subdirectory. In most cases overlays are invoked by kfctl by specifying the overlay to call within the app.yaml. An example of invoking the debug overlay is shown below:
apiVersion: kfdef.apps.kubeflow.org/v1alpha1
kind: KfDef
metadata:
creationTimestamp: null
labels:
app.kubernetes.io/name: experiments
name: experiments
namespace: experiments
spec:
appdir: /Users/kdkasrav/experiments
componentParams:
profiles:
- name: overlay
value: debug
- name: project
components:
- profiles
manifestsRepo: /Users/kdkasrav/experiments/.cache/manifests/pull/31/head
packageManager: kustomize@pull/31
packages:
- profiles
project: constant-cubist-173123
repo: /Users/kdkasrav/experiments/.cache/kubeflow/pull/3108/head/kubeflow
useBasicAuth: false
useIstio: false
version: pull/3108
status: {}
Calling kfctl generate all
will produce the profiles resources with a modified Deployment that allows remotely attach to dlv running the profile-controller .
Using profiles as the use case
profiles
├── base
│ └── kustomization.yaml
└── overlays
├── debug
│ └── kustomization.yaml
└── devices
└── kustomization.yaml
Normally kustomize provides the ability to overlay a 'base' set of resources with changes that are merged into the base from resources that are located under an overlays directory. Kustomize doesn't provide for an easy way to combine more than one overlay for example debug and devices. However kustomize has several feature requests to allow this and combining overlays is possible if one were to create a kustomization.yaml under profiles that included base and the kustomization directives in debug and devices. This requires some path corrections and some constraints within each kustomization but allows 'mixins' to be used in the manner described above. In order to 'mixin' debug and devices the app.yaml would add both overlays in the profiles componentParams as shown below
componentParams:
profiles:
- name: overlay
value: debug
- name: overlay
value: devices
The kustomization.yaml generated in .cache/manifests/master/profiles/ looks like
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
bases:
- base
commonLabels:
app.kubernetes.io/name: experiments
configMapGenerator:
- env: overlays/debug/params.env
name: parameters
configurations:
- overlays/debug/params.yaml
generatorOptions:
disableNameSuffixHash: true
namespace: experiments
patchesStrategicMerge:
- overlays/debug/deployment.yaml
- overlays/devices/deployment.yaml
vars:
- fieldref:
fieldPath: data.project
name: project
objref:
apiVersion: v1
kind: ConfigMap
name: parameters
- fieldref:
fieldPath: data.namespace
name: namespace
objref:
apiVersion: v1
kind: ConfigMap
name: parameters