kubectlkustomize

Adding items to a list with kubectl kustomize


I have base/foo.yaml that I want to apply to all my environments and it partially looks like this

Kubernetes:
  deploymentPatches:
    - patch: |-
      - {"op": "add", "path": "/spec/template/spec/volumes/-", "value": {"name": "volume", "secret": {"secretName": "my-secret"}}}
      - {"op": "add", "path": "/spec/template/spec/containers/0/volumeMounts/-", "value": {"mountPath": "/connections", "name": "volume"}}

Now I want to add environment-specific patches as well so my end goal after running e.g. kubectl kustomize accept should either be

Kubernetes:
  deploymentPatches:
    - patch: |-
      - {"op": "add", "path": "/spec/template/spec/volumes/-", "value": {"name": "volume", "secret": {"secretName": "my-secret"}}}
      - {"op": "add", "path": "/spec/template/spec/containers/0/volumeMounts/-", "value": {"mountPath": "/connections", "name": "volume"}}
      - {"op": "add", "path": "/spec/template/spec/containers/0/env/-", "value": {"name": "MY_ENVIRONMENT", "value": "accept"}}

or

Kubernetes:
  deploymentPatches:
    - patch: |-
      - {"op": "add", "path": "/spec/template/spec/volumes/-", "value": {"name": "volume", "secret": {"secretName": "my-secret"}}}
      - {"op": "add", "path": "/spec/template/spec/containers/0/volumeMounts/-", "value": {"mountPath": "/connections", "name": "volume"}}
    - patch: |-
      - {"op": "add", "path": "/spec/template/spec/containers/0/env/-", "value": {"name": "MY_ENVIRONMENT", "value": "accept"}}

How would I go about setting up my kustomize config to accomplish this? I've tried the following thus far:

kustomize.yaml

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
bases:
  - ../base
patchesStrategicMerge:
  - foo.yaml

accept/foo.yaml

Kubernetes:
  deploymentPatches:
    - patch: |-
      - {"op": "add", "path": "/spec/template/spec/containers/0/env/-", "value": {"name": "MY_ENVIRONMENT", "value": "accept"}}

Solution

  • The issue I was experiencing is explained in the strategic merge patch docs;

    In the standard JSON merge patch, JSON objects are always merged but lists are always replaced. Often that isn't what we want.

    To solve this problem, Strategic Merge Patch uses the go struct tag of the API objects to determine what lists should be merged and which ones should not.

    That is why it works to add additional containers (if you use different names for the containers you want to append) with patchesStrategicMerge.

    However, the objects and lists I was trying to append items to, were not setup that way and was therefor just replaced.

    Since I'm not in a position to change the setup, the solution for me was to resort to patchesJson6902.

    patch.yaml

    - op: add
      path: /spec/Kubernetes/deploymentPatches/-
      value:
        patch: |-
          - op: add
            path: /spec/template/spec/containers/0/env/-
            value:
              name: MY_ENVIRONMENT
              value: accept
    

    kustomization.yaml

    apiVersion: kustomize.config.k8s.io/v1beta1
    kind: Kustomization
    bases:
      - ../base
    patchesJson6902:
    - target:
        group: mygroup
        version: v1
        kind: myobject
        name: myname
      path: patch.yaml