diff --git a/README.md b/README.md index 308283e..b570752 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,22 @@ krmfnbuiltin is a [kustomize plugin](https://kubectl.docs.kubernetes.io/guides/extending_kustomize/) that you can use to perform in place transformation in your kustomize projects. + + + +
+ Table of Contents +
    +
  1. Rationale
  2. +
  3. Usage Example
  4. +
  5. Use of generators
  6. +
  7. Installation
  8. +
  9. Argo CD integration
  10. +
  11. Related projects
  12. +
+
+ + ## Rationale `kustomize fn run` allows performing _in place_ transformation of KRM @@ -16,7 +32,7 @@ a `container` or `exec` annotation in the transformer resource pointing to a krm function docker image or executable. `krmfnbuiltin` provides both the image and executable allowing the use of any -builtin transformer. +builtin transformer or generator. ## Usage Example @@ -142,6 +158,200 @@ source: You now can commit the 10 modified manifests in your branch and deploy the applications. +## Use of generators + +Let's imagine that one or more of your applications use an Helm chart that in +turn creates applications. You pass the repo URL and target branch as values to +the Helm Chart with the following: + +```yaml +helm: + parameters: + - name: common.targetRevision + value: main + - name: common.repoURL + value: https://github.com/kaweezle/autocloud.git +``` + +For that particular transformation, JSON patches are not practical: + +```yaml +patch: |- + - op: replace + path: /spec/source/repoURL + value: https://github.com/antoinemartin/autocloud.git + - op: replace + path: /spec/source/targetRevision + value: deploy/citest + - op: replace + path: /spec/source/helm/parameters/1/value + value: https://github.com/antoinemartin/autocloud.git + - op: replace + path: /spec/source/helm/parameters/0/value + value: deploy/citest +``` + +You need to hardcode the index of the value to replace in the array, which is +error prone, and you start duplicating values. + +It would be better to have a unique _source_ with the right values, and do +`replacements` where needed. You can inject the values with a +`ConfigMapGenerator` + +```yaml +# 01_configmap-generator.yaml +apiVersion: builtin +# Use this to inject current git values +# kind: GitConfigMapGenerator +kind: ConfigMapGenerator +metadata: + name: configuration-map + annotations: + config.kubernetes.io/function: | + exec: + path: krmfnbuiltin +# When using GitConfigMapGenerator, these are automatically injected +literals: + - repoURL=https://github.com/kaweezle/autocloud.git + - targetRevision=deploy/citest +``` + +And then use a `ReplacementTransformer` to inject the values: + +```yaml +# 02_replacement-transformer.yaml +apiVersion: builtin +kind: ReplacementTransformer +metadata: + name: replacement-transformer + namespace: argocd + annotations: + # Put this annotation in the last transformation to remove generated resources + config.kubernetes.io/prune-local: "true" + config.kubernetes.io/function: | + exec: + path: krmfnbuiltin +replacements: + - source: + kind: ConfigMap + fieldPath: data.repoURL + targets: + - select: + kind: Application + annotationSelector: "autocloud/local=true" + fieldPaths: + - spec.source.repoURL + # This field specification is not related to the index + - spec.source.helm.parameters.[name=common.repoURL].value + - source: + kind: ConfigMap + fieldPath: data.targetRevision + targets: + - select: + kind: Application + annotationSelector: "autocloud/local=true" + fieldPaths: + - spec.source.targetRevision + - spec.source.helm.parameters.[name=common.targetRevision].value +``` + +Some remarks: + +- ✔️ The actual values (repo url and revision) are only specified once. +- ✔️ `spec.source.helm.parameters.[name=common.repoURL].value` is path more + specific than `/spec/source/helm/parameters/1/value`. +- ✔️ The functions file names are prefixed with a number prefix (`01_`, `02_`) + in order to ensure that the functions are executed in the right order. +- ✔️ In the last transformation, we add the following annotation: + + ```yaml + config.kubernetes.io/prune-local: "true" + ``` + + In order to avoid saving the generated resources. This is due to an issue in + kustomize that doesn't filter out resources annotated with + `config.kubernetes.io/local-config` in the case you are using + `kustomize fn run` (although it works with `kustomize build`). + +As a convenience, for this specific use case, we have added a +`GitConfigMapGenerator` that automatically adds the relevant resources, while +some people may consider this overkill. + +## Installation + +With each [Release](https://github.com/kaweezle/krmfnbuiltin/releases), we +provide binaries for most platforms as well as Alpine based packages. Typically, +you would install it on linux with the following command: + +```console +> KRMFNBUILTIN_VERSION="v0.1.0" +> curl -sLo /usr/local/bin/krmfnbuiltin https://github.com/kaweezle/krmfnbuiltin/releases/download/${KRMFNBUILTIN_VERSION}/krmfnbuiltin_${KRMFNBUILTIN_VERSION}_linux_amd64 +``` + +## Argo CD integration + +`krmfnbuiltin` is **NOT** primarily meant to be used inside Argo CD, but instead +to perform _structural_ modifications to the source **BEFORE** the commit. + +Anyway, to use `krmfnbuiltin` with Argo CD, you need to: + +- Make the `krmfnbuiltin` binary available to the `argo-repo-server` pod. +- Have Argo CD run kustomize with the `--enable-alpha-plugins --enable-exec` + parameters. + +To add krmfnbuiltin on argo-repo-server, the +[Argo CD documentation](https://argo-cd.readthedocs.io/en/stable/operator-manual/custom_tools/) +provides different methods to make custom tools available. + +If you get serious about Argo CD, you will probably end up cooking your own +image. This +[docker file](https://github.com/antoinemartin/autocloud/blob/deploy/citest/repo-server/Dockerfile#L45) +shows how to use the above installation instructions in your image. To +summarize: + +```Dockerfile +FROM argoproj/argocd:latest + +ARG KRMFNBUILTIN_VERSION=v0.1.0 + +# Switch to root for the ability to perform install +USER root + +# Install tools +RUN apt-get update && \ + apt-get install -y curl && \ + apt-get clean && \ + rm -rf /var/lib/apt/lists/* && \ + curl -sLo /usr/local/bin/krmfnbuiltin https://github.com/kaweezle/krmfnbuiltin/releases/download/${KRMFNBUILTIN_VERSION}/krmfnbuiltin_${KRMFNBUILTIN_VERSION}_linux_amd64 + +USER argocd +``` + +You also need to patch the `argo-cm` config map to add the parameters. The +following is a strategic merge patch for it: + +```yaml +# argocd-cm.yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: argocd-cm +data: + # Options to enable exec plugins (krmfnsops). + kustomize.buildOptions: "--enable-alpha-plugins --enable-exec" + ... +``` + +## Related projects + +[kpt], from Google, takes this in place transformation principle to another +level by making resource configuration packages similar to docker images. In +this model, a generator or a transformer along its parameters in much like a +line in a dockerfile. It takes a current configuration as source and generates a +new configuration after transformation. + +While it has not been tested, krmfnbuiltin should work with [kpt]. + [kpt]: https://kpt.dev/guides/rationale diff --git a/tests/applications/argocd.yaml b/tests/applications/argocd.yaml index bc8cf97..e88b9e7 100644 --- a/tests/applications/argocd.yaml +++ b/tests/applications/argocd.yaml @@ -19,6 +19,12 @@ spec: path: packages/argocd repoURL: https://github.com/anotherproject/anothergit targetRevision: main + helm: + parameters: + - name: common.targetRevision + value: main + - name: common.repoURL + value: https://github.com/anotherproject/anothergit syncPolicy: automated: allowEmpty: true diff --git a/tests/compare/argocd.expected.yaml b/tests/compare/argocd.expected.yaml index f371d87..0d94d20 100644 --- a/tests/compare/argocd.expected.yaml +++ b/tests/compare/argocd.expected.yaml @@ -19,6 +19,12 @@ spec: path: packages/argocd repoURL: https://github.com/antoinemartin/autocloud.git targetRevision: deploy/citest + helm: + parameters: + - name: common.targetRevision + value: deploy/citest + - name: common.repoURL + value: https://github.com/antoinemartin/autocloud.git syncPolicy: automated: allowEmpty: true diff --git a/tests/compare/argocd.original.yaml b/tests/compare/argocd.original.yaml index bc8cf97..e88b9e7 100644 --- a/tests/compare/argocd.original.yaml +++ b/tests/compare/argocd.original.yaml @@ -19,6 +19,12 @@ spec: path: packages/argocd repoURL: https://github.com/anotherproject/anothergit targetRevision: main + helm: + parameters: + - name: common.targetRevision + value: main + - name: common.repoURL + value: https://github.com/anotherproject/anothergit syncPolicy: automated: allowEmpty: true diff --git a/tests/functions/patch-transformer.yaml b/tests/functions/patch-transformer.yaml index 9b14c18..9ad6376 100644 --- a/tests/functions/patch-transformer.yaml +++ b/tests/functions/patch-transformer.yaml @@ -13,6 +13,12 @@ patch: |- - op: replace path: /spec/source/targetRevision value: deploy/citest + - op: replace + path: /spec/source/helm/parameters/1/value + value: https://github.com/antoinemartin/autocloud.git + - op: replace + path: /spec/source/helm/parameters/0/value + value: deploy/citest target: group: argoproj.io version: v1alpha1 diff --git a/tests/functions2/02_replacement-transformer.yaml b/tests/functions2/02_replacement-transformer.yaml index b7e5768..4d69b70 100644 --- a/tests/functions2/02_replacement-transformer.yaml +++ b/tests/functions2/02_replacement-transformer.yaml @@ -18,6 +18,7 @@ replacements: annotationSelector: "autocloud/local=true" fieldPaths: - spec.source.repoURL + - spec.source.helm.parameters.[name=common.repoURL].value - source: kind: ConfigMap fieldPath: data.targetRevision @@ -27,3 +28,4 @@ replacements: annotationSelector: "autocloud/local=true" fieldPaths: - spec.source.targetRevision + - spec.source.helm.parameters.[name=common.targetRevision].value